warnings: mute unused variable warning
[midnight-commander.git] / src / vfs / sftpfs / file.c
blob59db42777c45a229acd1d861db7da4637600a4a2
1 /* Virtual File System: SFTP file system.
2 The internal functions: files
4 Copyright (C) 2011-2024
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 <errno.h> /* ENOENT, EACCES */
31 #include <libssh2.h>
32 #include <libssh2_sftp.h>
34 #include "lib/global.h"
35 #include "lib/util.h"
37 #include "internal.h"
39 /*** global variables ****************************************************************************/
41 /*** file scope macro definitions ****************************************************************/
43 #define SFTP_FILE_HANDLER(a) ((sftpfs_file_handler_t *) a)
45 /*** file scope type declarations ****************************************************************/
47 typedef struct
49 vfs_file_handler_t base; /* base class */
51 LIBSSH2_SFTP_HANDLE *handle;
52 int flags;
53 mode_t mode;
54 } sftpfs_file_handler_t;
56 /*** forward declarations (file scope functions) *************************************************/
58 /*** file scope variables ************************************************************************/
60 /* --------------------------------------------------------------------------------------------- */
61 /*** file scope functions ************************************************************************/
62 /* --------------------------------------------------------------------------------------------- */
63 /**
64 * Reopen file by file handle.
66 * @param fh the file handler
67 * @param mcerror pointer to the error handler
69 static void
70 sftpfs_reopen (vfs_file_handler_t *fh, GError **mcerror)
72 sftpfs_file_handler_t *file = SFTP_FILE_HANDLER (fh);
73 int flags;
74 mode_t mode;
76 g_return_if_fail (mcerror == NULL || *mcerror == NULL);
78 flags = file->flags;
79 mode = file->mode;
81 sftpfs_close_file (fh, mcerror);
82 sftpfs_open_file (fh, flags, mode, mcerror);
85 /* --------------------------------------------------------------------------------------------- */
87 static int
88 sftpfs_file__handle_error (sftpfs_super_t *super, int sftp_res, GError **mcerror)
90 if (sftpfs_is_sftp_error (super->sftp_session, sftp_res, LIBSSH2_FX_PERMISSION_DENIED))
91 return -EACCES;
93 if (sftpfs_is_sftp_error (super->sftp_session, sftp_res, LIBSSH2_FX_NO_SUCH_FILE))
94 return -ENOENT;
96 if (!sftpfs_waitsocket (super, sftp_res, mcerror))
97 return -1;
99 return 0;
102 /* --------------------------------------------------------------------------------------------- */
103 /*** public functions ****************************************************************************/
104 /* --------------------------------------------------------------------------------------------- */
106 vfs_file_handler_t *
107 sftpfs_fh_new (struct vfs_s_inode *ino, gboolean changed)
109 sftpfs_file_handler_t *fh;
111 fh = g_new0 (sftpfs_file_handler_t, 1);
112 vfs_s_init_fh (VFS_FILE_HANDLER (fh), ino, changed);
114 return VFS_FILE_HANDLER (fh);
117 /* --------------------------------------------------------------------------------------------- */
119 * Open new SFTP file.
121 * @param fh the file handler
122 * @param flags flags (see man 2 open)
123 * @param mode mode (see man 2 open)
124 * @param mcerror pointer to the error handler
125 * @return TRUE if connection was created successfully, FALSE otherwise
128 gboolean
129 sftpfs_open_file (vfs_file_handler_t *fh, int flags, mode_t mode, GError **mcerror)
131 unsigned long sftp_open_flags = 0;
132 int sftp_open_mode = 0;
133 gboolean do_append = FALSE;
134 sftpfs_file_handler_t *file = SFTP_FILE_HANDLER (fh);
135 sftpfs_super_t *super = SFTP_SUPER (fh->ino->super);
136 char *name;
137 const GString *fixfname;
139 (void) mode;
140 mc_return_val_if_error (mcerror, FALSE);
142 name = vfs_s_fullpath (vfs_sftpfs_ops, fh->ino);
143 if (name == NULL)
144 return FALSE;
146 if ((flags & O_CREAT) != 0 || (flags & O_WRONLY) != 0)
148 sftp_open_flags = (flags & O_WRONLY) != 0 ? LIBSSH2_FXF_WRITE : 0;
149 sftp_open_flags |= (flags & O_CREAT) != 0 ? LIBSSH2_FXF_CREAT : 0;
150 if ((flags & O_APPEND) != 0)
152 sftp_open_flags |= LIBSSH2_FXF_APPEND;
153 do_append = TRUE;
155 sftp_open_flags |= (flags & O_TRUNC) != 0 ? LIBSSH2_FXF_TRUNC : 0;
157 sftp_open_mode = LIBSSH2_SFTP_S_IRUSR |
158 LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IROTH;
160 else
161 sftp_open_flags = LIBSSH2_FXF_READ;
163 fixfname = sftpfs_fix_filename (name);
165 while (TRUE)
167 int libssh_errno;
169 file->handle =
170 libssh2_sftp_open_ex (super->sftp_session, fixfname->str, fixfname->len,
171 sftp_open_flags, sftp_open_mode, LIBSSH2_SFTP_OPENFILE);
172 if (file->handle != NULL)
173 break;
175 libssh_errno = libssh2_session_last_errno (super->session);
176 if (libssh_errno != LIBSSH2_ERROR_EAGAIN)
178 sftpfs_ssherror_to_gliberror (super, libssh_errno, mcerror);
179 g_free (name);
180 return FALSE;
184 g_free (name);
186 file->flags = flags;
187 file->mode = mode;
189 if (do_append)
191 struct stat file_info = {
192 .st_dev = 0
194 /* In case of
196 struct stat file_info = { 0 };
198 gcc < 4.7 [1] generates the following:
200 error: missing initializer [-Werror=missing-field-initializers]
201 error: (near initialization for 'file_info.st_dev') [-Werror=missing-field-initializers]
203 [1] http://stackoverflow.com/questions/13373695/how-to-remove-the-warning-in-gcc-4-6-missing-initializer-wmissing-field-initi/27461062#27461062
206 if (sftpfs_fstat (fh, &file_info, mcerror) == 0)
207 libssh2_sftp_seek64 (file->handle, file_info.st_size);
209 return TRUE;
212 /* --------------------------------------------------------------------------------------------- */
214 * Stats the file specified by the file descriptor.
216 * @param data file handler
217 * @param buf buffer for store stat-info
218 * @param mcerror pointer to the error handler
219 * @return 0 if success, negative value otherwise
223 sftpfs_fstat (void *data, struct stat *buf, GError **mcerror)
225 int res;
226 LIBSSH2_SFTP_ATTRIBUTES attrs;
227 vfs_file_handler_t *fh = VFS_FILE_HANDLER (data);
228 sftpfs_file_handler_t *sftpfs_fh = (sftpfs_file_handler_t *) data;
229 struct vfs_s_super *super = VFS_FILE_HANDLER_SUPER (fh);
230 sftpfs_super_t *sftpfs_super = SFTP_SUPER (super);
232 mc_return_val_if_error (mcerror, -1);
234 if (sftpfs_fh->handle == NULL)
235 return -1;
239 int err;
241 res = libssh2_sftp_fstat_ex (sftpfs_fh->handle, &attrs, 0);
242 if (res >= 0)
243 break;
245 err = sftpfs_file__handle_error (sftpfs_super, res, mcerror);
246 if (err < 0)
247 return err;
249 while (res == LIBSSH2_ERROR_EAGAIN);
251 sftpfs_attr_to_stat (&attrs, buf);
253 return 0;
256 /* --------------------------------------------------------------------------------------------- */
258 * Read up to 'count' bytes from the file descriptor 'fh' to the buffer starting at 'buffer'.
260 * @param fh file handler
261 * @param buffer buffer for data
262 * @param count data size
263 * @param mcerror pointer to the error handler
265 * @return 0 on success, negative value otherwise
268 ssize_t
269 sftpfs_read_file (vfs_file_handler_t *fh, char *buffer, size_t count, GError **mcerror)
271 ssize_t rc;
272 sftpfs_file_handler_t *file = SFTP_FILE_HANDLER (fh);
273 sftpfs_super_t *super;
275 mc_return_val_if_error (mcerror, -1);
277 if (fh == NULL)
279 mc_propagate_error (mcerror, 0, "%s",
280 _("sftp: No file handler data present for reading file"));
281 return -1;
284 super = SFTP_SUPER (VFS_FILE_HANDLER_SUPER (fh));
288 int err;
290 rc = libssh2_sftp_read (file->handle, buffer, count);
291 if (rc >= 0)
292 break;
294 err = sftpfs_file__handle_error (super, (int) rc, mcerror);
295 if (err < 0)
296 return err;
298 while (rc == LIBSSH2_ERROR_EAGAIN);
300 fh->pos = (off_t) libssh2_sftp_tell64 (file->handle);
302 return rc;
305 /* --------------------------------------------------------------------------------------------- */
308 * Write up to 'count' bytes from the buffer starting at 'buffer' to the descriptor 'fh'.
310 * @param fh file handler
311 * @param buffer buffer for data
312 * @param count data size
313 * @param mcerror pointer to the error handler
315 * @return 0 on success, negative value otherwise
318 ssize_t
319 sftpfs_write_file (vfs_file_handler_t *fh, const char *buffer, size_t count, GError **mcerror)
321 ssize_t rc;
322 sftpfs_file_handler_t *file = SFTP_FILE_HANDLER (fh);
323 sftpfs_super_t *super = SFTP_SUPER (VFS_FILE_HANDLER_SUPER (fh));
325 mc_return_val_if_error (mcerror, -1);
327 fh->pos = (off_t) libssh2_sftp_tell64 (file->handle);
331 int err;
333 rc = libssh2_sftp_write (file->handle, buffer, count);
334 if (rc >= 0)
335 break;
337 err = sftpfs_file__handle_error (super, (int) rc, mcerror);
338 if (err < 0)
339 return err;
341 while (rc == LIBSSH2_ERROR_EAGAIN);
343 return rc;
346 /* --------------------------------------------------------------------------------------------- */
349 * Close a file descriptor.
351 * @param fh file handler
352 * @param mcerror pointer to the error handler
354 * @return 0 on success, negative value otherwise
358 sftpfs_close_file (vfs_file_handler_t *fh, GError **mcerror)
360 int ret;
362 mc_return_val_if_error (mcerror, -1);
364 ret = libssh2_sftp_close (SFTP_FILE_HANDLER (fh)->handle);
366 return ret == 0 ? 0 : -1;
369 /* --------------------------------------------------------------------------------------------- */
372 * Reposition the offset of the open file associated with the file descriptor.
374 * @param fh file handler
375 * @param offset file offset
376 * @param whence method of seek (at begin, at current, at end)
377 * @param mcerror pointer to the error handler
379 * @return 0 on success, negative value otherwise
382 off_t
383 sftpfs_lseek (vfs_file_handler_t *fh, off_t offset, int whence, GError **mcerror)
385 sftpfs_file_handler_t *file = SFTP_FILE_HANDLER (fh);
387 mc_return_val_if_error (mcerror, 0);
389 switch (whence)
391 case SEEK_SET:
392 /* Need reopen file because:
393 "You MUST NOT seek during writing or reading a file with SFTP, as the internals use
394 outstanding packets and changing the "file position" during transit will results in
395 badness." */
396 if (fh->pos > offset || offset == 0)
398 sftpfs_reopen (fh, mcerror);
399 mc_return_val_if_error (mcerror, 0);
401 fh->pos = offset;
402 break;
403 case SEEK_CUR:
404 fh->pos += offset;
405 break;
406 case SEEK_END:
407 if (fh->pos > fh->ino->st.st_size - offset)
409 sftpfs_reopen (fh, mcerror);
410 mc_return_val_if_error (mcerror, 0);
412 fh->pos = fh->ino->st.st_size - offset;
413 break;
414 default:
415 break;
418 libssh2_sftp_seek64 (file->handle, fh->pos);
419 fh->pos = (off_t) libssh2_sftp_tell64 (file->handle);
421 return fh->pos;
424 /* --------------------------------------------------------------------------------------------- */