fb8cbac289692976f20d28ab5637b5f5f8b9c874
[midnight-commander.git] / src / vfs / sftpfs / file.c
blobfb8cbac289692976f20d28ab5637b5f5f8b9c874
1 /* Virtual File System: SFTP file system.
2 The internal functions: files
4 Copyright (C) 2011
5 The Free Software Foundation, Inc.
7 Written by:
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/>.
27 #include <config.h>
29 #include <libssh2.h>
30 #include <libssh2_sftp.h>
32 #include "lib/global.h"
34 #include "internal.h"
36 /*** global variables ****************************************************************************/
38 /*** file scope macro definitions ****************************************************************/
40 /*** file scope type declarations ****************************************************************/
42 typedef struct
44 LIBSSH2_SFTP_HANDLE *handle;
45 int flags;
46 mode_t mode;
47 } sftpfs_file_handler_data_t;
49 /*** file scope variables ************************************************************************/
51 /*** file scope functions ************************************************************************/
52 /* --------------------------------------------------------------------------------------------- */
53 /**
54 * Reopen file by file handle.
56 * @param file_handler the file handler data
57 * @param error pointer to the error handler
59 static void
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 /* --------------------------------------------------------------------------------------------- */
74 /**
75 * Open new SFTP file.
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
84 gboolean
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;
92 char *name;
94 (void) mode;
96 name = vfs_s_fullpath (&sftpfs_class, file_handler->ino);
97 if (name == NULL)
98 return FALSE;
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;
110 do_append = TRUE;
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;
117 else
118 sftp_open_flags = LIBSSH2_FXF_READ;
120 while (TRUE)
122 int libssh_errno;
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)
129 break;
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);
135 g_free (name);
136 return FALSE;
140 g_free (name);
142 file_handler_data->flags = flags;
143 file_handler_data->mode = mode;
144 file_handler->data = file_handler_data;
146 if (do_append)
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);
153 return TRUE;
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)
169 int res;
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)
177 return -1;
181 res = libssh2_sftp_fstat_ex (sftpfs_fh->handle, &attrs, 0);
182 if (res >= 0)
183 break;
185 if (res != LIBSSH2_ERROR_EAGAIN)
187 sftpfs_ssherror_to_gliberror (super_data, res, error);
188 return -1;
191 sftpfs_waitsocket (super_data, error);
192 if (error != NULL && *error != NULL)
193 return -1;
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;
216 return 0;
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
231 ssize_t
232 sftpfs_read_file (vfs_file_handler_t * file_handler, char *buffer, size_t count, GError ** error)
234 ssize_t rc;
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"));
241 return -1;
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);
250 if (rc >= 0)
251 break;
253 if (rc != LIBSSH2_ERROR_EAGAIN)
255 sftpfs_ssherror_to_gliberror (super_data, rc, error);
256 return -1;
259 sftpfs_waitsocket (super_data, error);
260 if (error != NULL && *error != NULL)
261 return -1;
263 while (rc == LIBSSH2_ERROR_EAGAIN);
265 file_handler->pos = (off_t) libssh2_sftp_tell64 (file_handler_data->handle);
267 return rc;
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
283 ssize_t
284 sftpfs_write_file (vfs_file_handler_t * file_handler, const char *buffer, size_t count,
285 GError ** error)
287 ssize_t rc;
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);
299 if (rc >= 0)
300 break;
302 if (rc != LIBSSH2_ERROR_EAGAIN)
304 sftpfs_ssherror_to_gliberror (super_data, rc, error);
305 return -1;
308 sftpfs_waitsocket (super_data, error);
309 if (error != NULL && *error != NULL)
310 return -1;
312 while (rc == LIBSSH2_ERROR_EAGAIN);
314 return rc;
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;
333 (void) error;
335 file_handler_data = (sftpfs_file_handler_data_t *) file_handler->data;
336 if (file_handler_data == NULL)
337 return -1;
339 libssh2_sftp_close (file_handler_data->handle);
341 g_free (file_handler_data);
342 return 0;
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
358 off_t
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;
365 switch (whence)
367 case SEEK_SET:
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
371 badness." */
372 if (file_handler->pos > offset || offset == 0)
374 sftpfs_reopen (file_handler, error);
375 if (error != NULL && *error != NULL)
376 return 0;
378 file_handler->pos = offset;
379 break;
380 case SEEK_CUR:
381 file_handler->pos += offset;
382 break;
383 case SEEK_END:
384 if (file_handler->pos > file_handler->ino->st.st_size - offset)
386 sftpfs_reopen (file_handler, error);
387 if (error != NULL && *error != NULL)
388 return 0;
390 file_handler->pos = file_handler->ino->st.st_size - offset;
391 break;
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 /* --------------------------------------------------------------------------------------------- */