Ticket #3431: add missing default cases.
[midnight-commander.git] / src / vfs / sftpfs / file.c
blob3ce9f3651037901cbf3aaad52e02feb4b6f6ec9e
1 /* Virtual File System: SFTP file system.
2 The internal functions: files
4 Copyright (C) 2011-2015
5 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"
33 #include "lib/util.h"
35 #include "internal.h"
37 /*** global variables ****************************************************************************/
39 /*** file scope macro definitions ****************************************************************/
41 /*** file scope type declarations ****************************************************************/
43 typedef struct
45 LIBSSH2_SFTP_HANDLE *handle;
46 int flags;
47 mode_t mode;
48 } sftpfs_file_handler_data_t;
50 /*** file scope variables ************************************************************************/
52 /*** file scope functions ************************************************************************/
53 /* --------------------------------------------------------------------------------------------- */
54 /**
55 * Reopen file by file handle.
57 * @param file_handler the file handler data
58 * @param mcerror pointer to the error handler
60 static void
61 sftpfs_reopen (vfs_file_handler_t * file_handler, GError ** mcerror)
63 sftpfs_file_handler_data_t *file_handler_data;
64 int flags;
65 mode_t mode;
67 g_return_if_fail (mcerror == NULL || *mcerror == NULL);
69 file_handler_data = (sftpfs_file_handler_data_t *) file_handler->data;
70 flags = file_handler_data->flags;
71 mode = file_handler_data->mode;
73 sftpfs_close_file (file_handler, mcerror);
74 sftpfs_open_file (file_handler, flags, mode, mcerror);
77 /* --------------------------------------------------------------------------------------------- */
78 /*** public functions ****************************************************************************/
79 /* --------------------------------------------------------------------------------------------- */
80 /**
81 * Open new SFTP file.
83 * @param file_handler the file handler data
84 * @param flags flags (see man 2 open)
85 * @param mode mode (see man 2 open)
86 * @param mcerror pointer to the error handler
87 * @return TRUE if connection was created successfully, FALSE otherwise
90 gboolean
91 sftpfs_open_file (vfs_file_handler_t * file_handler, int flags, mode_t mode, GError ** mcerror)
93 unsigned long sftp_open_flags = 0;
94 int sftp_open_mode = 0;
95 gboolean do_append = FALSE;
96 sftpfs_file_handler_data_t *file_handler_data;
97 sftpfs_super_data_t *super_data;
98 char *name;
100 (void) mode;
101 mc_return_val_if_error (mcerror, FALSE);
103 name = vfs_s_fullpath (&sftpfs_class, file_handler->ino);
104 if (name == NULL)
105 return FALSE;
107 super_data = (sftpfs_super_data_t *) file_handler->ino->super->data;
108 file_handler_data = g_new0 (sftpfs_file_handler_data_t, 1);
110 if ((flags & O_CREAT) != 0 || (flags & O_WRONLY) != 0)
112 sftp_open_flags = (flags & O_WRONLY) != 0 ? LIBSSH2_FXF_WRITE : 0;
113 sftp_open_flags |= (flags & O_CREAT) != 0 ? LIBSSH2_FXF_CREAT : 0;
114 if ((flags & O_APPEND) != 0)
116 sftp_open_flags |= LIBSSH2_FXF_APPEND;
117 do_append = TRUE;
119 sftp_open_flags |= (flags & O_TRUNC) != 0 ? LIBSSH2_FXF_TRUNC : 0;
121 sftp_open_mode = LIBSSH2_SFTP_S_IRUSR |
122 LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IROTH;
124 else
125 sftp_open_flags = LIBSSH2_FXF_READ;
127 while (TRUE)
129 int libssh_errno;
131 file_handler_data->handle =
132 libssh2_sftp_open (super_data->sftp_session, sftpfs_fix_filename (name),
133 sftp_open_flags, sftp_open_mode);
135 if (file_handler_data->handle != NULL)
136 break;
138 libssh_errno = libssh2_session_last_errno (super_data->session);
139 if (libssh_errno != LIBSSH2_ERROR_EAGAIN)
141 sftpfs_ssherror_to_gliberror (super_data, libssh_errno, mcerror);
142 g_free (name);
143 g_free (file_handler_data);
144 return FALSE;
148 g_free (name);
150 file_handler_data->flags = flags;
151 file_handler_data->mode = mode;
152 file_handler->data = file_handler_data;
154 if (do_append)
156 struct stat file_info;
158 if (sftpfs_fstat (file_handler, &file_info, mcerror) == 0)
159 libssh2_sftp_seek64 (file_handler_data->handle, file_info.st_size);
161 return TRUE;
164 /* --------------------------------------------------------------------------------------------- */
166 * Stats the file specified by the file descriptor.
168 * @param data file data handler
169 * @param buf buffer for store stat-info
170 * @param mcerror pointer to the error handler
171 * @return 0 if success, negative value otherwise
175 sftpfs_fstat (void *data, struct stat *buf, GError ** mcerror)
177 int res;
178 LIBSSH2_SFTP_ATTRIBUTES attrs;
179 vfs_file_handler_t *fh = (vfs_file_handler_t *) data;
180 sftpfs_file_handler_data_t *sftpfs_fh = fh->data;
181 struct vfs_s_super *super = fh->ino->super;
182 sftpfs_super_data_t *super_data = (sftpfs_super_data_t *) super->data;
184 mc_return_val_if_error (mcerror, -1);
186 if (sftpfs_fh->handle == NULL)
187 return -1;
191 res = libssh2_sftp_fstat_ex (sftpfs_fh->handle, &attrs, 0);
192 if (res >= 0)
193 break;
195 if (res != LIBSSH2_ERROR_EAGAIN)
197 sftpfs_ssherror_to_gliberror (super_data, res, mcerror);
198 return -1;
201 sftpfs_waitsocket (super_data, mcerror);
202 mc_return_val_if_error (mcerror, -1);
204 while (res == LIBSSH2_ERROR_EAGAIN);
206 if ((attrs.flags & LIBSSH2_SFTP_ATTR_UIDGID) != 0)
208 buf->st_uid = attrs.uid;
209 buf->st_gid = attrs.gid;
212 if ((attrs.flags & LIBSSH2_SFTP_ATTR_ACMODTIME) != 0)
214 buf->st_atime = attrs.atime;
215 buf->st_mtime = attrs.mtime;
216 buf->st_ctime = attrs.mtime;
219 if ((attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) != 0)
220 buf->st_size = attrs.filesize;
222 if ((attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) != 0)
223 buf->st_mode = attrs.permissions;
225 return 0;
228 /* --------------------------------------------------------------------------------------------- */
230 * Read up to 'count' bytes from the file descriptor 'file_handler' to the buffer starting at 'buffer'.
232 * @param file_handler file data handler
233 * @param buffer buffer for data
234 * @param count data size
235 * @param mcerror pointer to the error handler
237 * @return 0 on success, negative value otherwise
240 ssize_t
241 sftpfs_read_file (vfs_file_handler_t * file_handler, char *buffer, size_t count, GError ** mcerror)
243 ssize_t rc;
244 sftpfs_file_handler_data_t *file_handler_data;
245 sftpfs_super_data_t *super_data;
247 mc_return_val_if_error (mcerror, -1);
249 if (file_handler == NULL || file_handler->data == NULL)
251 mc_propagate_error (mcerror, -1, "%s",
252 _("sftp: No file handler data present for reading file"));
253 return -1;
256 file_handler_data = file_handler->data;
257 super_data = (sftpfs_super_data_t *) file_handler->ino->super->data;
261 rc = libssh2_sftp_read (file_handler_data->handle, buffer, count);
262 if (rc >= 0)
263 break;
265 if (rc != LIBSSH2_ERROR_EAGAIN)
267 sftpfs_ssherror_to_gliberror (super_data, rc, mcerror);
268 return -1;
271 sftpfs_waitsocket (super_data, mcerror);
272 mc_return_val_if_error (mcerror, -1);
274 while (rc == LIBSSH2_ERROR_EAGAIN);
276 file_handler->pos = (off_t) libssh2_sftp_tell64 (file_handler_data->handle);
278 return rc;
281 /* --------------------------------------------------------------------------------------------- */
284 * Write up to 'count' bytes from the buffer starting at 'buffer' to the descriptor 'file_handler'.
286 * @param file_handler file data handler
287 * @param buffer buffer for data
288 * @param count data size
289 * @param mcerror pointer to the error handler
291 * @return 0 on success, negative value otherwise
294 ssize_t
295 sftpfs_write_file (vfs_file_handler_t * file_handler, const char *buffer, size_t count,
296 GError ** mcerror)
298 ssize_t rc;
299 sftpfs_file_handler_data_t *file_handler_data;
300 sftpfs_super_data_t *super_data;
302 mc_return_val_if_error (mcerror, -1);
304 file_handler_data = (sftpfs_file_handler_data_t *) file_handler->data;
305 super_data = (sftpfs_super_data_t *) file_handler->ino->super->data;
307 file_handler->pos = (off_t) libssh2_sftp_tell64 (file_handler_data->handle);
311 rc = libssh2_sftp_write (file_handler_data->handle, buffer, count);
312 if (rc >= 0)
313 break;
315 if (rc != LIBSSH2_ERROR_EAGAIN)
317 sftpfs_ssherror_to_gliberror (super_data, rc, mcerror);
318 return -1;
321 sftpfs_waitsocket (super_data, mcerror);
322 mc_return_val_if_error (mcerror, -1);
324 while (rc == LIBSSH2_ERROR_EAGAIN);
326 return rc;
329 /* --------------------------------------------------------------------------------------------- */
332 * Close a file descriptor.
334 * @param file_handler file data handler
335 * @param mcerror pointer to the error handler
337 * @return 0 on success, negative value otherwise
341 sftpfs_close_file (vfs_file_handler_t * file_handler, GError ** mcerror)
343 sftpfs_file_handler_data_t *file_handler_data;
345 mc_return_val_if_error (mcerror, -1);
347 file_handler_data = (sftpfs_file_handler_data_t *) file_handler->data;
348 if (file_handler_data == NULL)
349 return -1;
351 libssh2_sftp_close (file_handler_data->handle);
353 g_free (file_handler_data);
354 return 0;
357 /* --------------------------------------------------------------------------------------------- */
360 * Reposition the offset of the open file associated with the file descriptor.
362 * @param file_handler file data handler
363 * @param offset file offset
364 * @param whence method of seek (at begin, at current, at end)
365 * @param mcerror pointer to the error handler
367 * @return 0 on success, negative value otherwise
370 off_t
371 sftpfs_lseek (vfs_file_handler_t * file_handler, off_t offset, int whence, GError ** mcerror)
373 sftpfs_file_handler_data_t *file_handler_data;
375 mc_return_val_if_error (mcerror, 0);
377 switch (whence)
379 case SEEK_SET:
380 /* Need reopen file because:
381 "You MUST NOT seek during writing or reading a file with SFTP, as the internals use
382 outstanding packets and changing the "file position" during transit will results in
383 badness." */
384 if (file_handler->pos > offset || offset == 0)
386 sftpfs_reopen (file_handler, mcerror);
387 mc_return_val_if_error (mcerror, 0);
389 file_handler->pos = offset;
390 break;
391 case SEEK_CUR:
392 file_handler->pos += offset;
393 break;
394 case SEEK_END:
395 if (file_handler->pos > file_handler->ino->st.st_size - offset)
397 sftpfs_reopen (file_handler, mcerror);
398 mc_return_val_if_error (mcerror, 0);
400 file_handler->pos = file_handler->ino->st.st_size - offset;
401 break;
402 default:
403 break;
406 file_handler_data = (sftpfs_file_handler_data_t *) file_handler->data;
408 libssh2_sftp_seek64 (file_handler_data->handle, file_handler->pos);
409 file_handler->pos = (off_t) libssh2_sftp_tell64 (file_handler_data->handle);
411 return file_handler->pos;
414 /* --------------------------------------------------------------------------------------------- */