Ticket #3917: preserve atime/mtime over sftpfs.
[midnight-commander.git] / src / vfs / sftpfs / vfs_class.c
bloba75d5b4531ef1fdcc2272defbb40d930f0c86abd
1 /* Virtual File System: SFTP file system.
2 The VFS class functions
4 Copyright (C) 2011-2018
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>
28 #include <errno.h>
30 #include "lib/global.h"
31 #include "lib/widget.h"
32 #include "lib/vfs/gc.h"
33 #include "lib/tty/tty.h" /* tty_enable_interrupt_key () */
35 #include "internal.h"
37 /*** global variables ****************************************************************************/
39 struct vfs_class sftpfs_class;
41 /*** file scope macro definitions ****************************************************************/
43 /*** file scope type declarations ****************************************************************/
45 /*** file scope variables ************************************************************************/
47 /*** file scope functions ************************************************************************/
48 /* --------------------------------------------------------------------------------------------- */
49 /**
50 * Callback for VFS-class init action.
52 * @param me structure of VFS class
55 static int
56 sftpfs_cb_init (struct vfs_class *me)
58 (void) me;
60 if (libssh2_init (0) != 0)
61 return 0;
63 sftpfs_filename_buffer = g_string_new ("");
64 sftpfs_init_config_variables_patterns ();
65 return 1;
68 /* --------------------------------------------------------------------------------------------- */
69 /**
70 * Callback for VFS-class deinit action.
72 * @param me structure of VFS class
75 static void
76 sftpfs_cb_done (struct vfs_class *me)
78 (void) me;
80 sftpfs_deinit_config_variables_patterns ();
81 g_string_free (sftpfs_filename_buffer, TRUE);
82 libssh2_exit ();
85 /* --------------------------------------------------------------------------------------------- */
86 /**
87 * Callback for opening file.
89 * @param vpath path to file
90 * @param flags flags (see man 2 open)
91 * @param mode mode (see man 2 open)
92 * @return file data handler if success, NULL otherwise
95 static void *
96 sftpfs_cb_open (const vfs_path_t * vpath, int flags, mode_t mode)
98 vfs_file_handler_t *file_handler;
99 const vfs_path_element_t *path_element;
100 struct vfs_s_super *super;
101 const char *path_super;
102 struct vfs_s_inode *path_inode;
103 GError *mcerror = NULL;
104 gboolean is_changed = FALSE;
106 path_element = vfs_path_get_by_index (vpath, -1);
108 path_super = vfs_s_get_path (vpath, &super, 0);
109 if (path_super == NULL)
110 return NULL;
112 path_inode = vfs_s_find_inode (path_element->class, super, path_super, LINK_FOLLOW, FL_NONE);
113 if (path_inode != NULL && ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)))
115 path_element->class->verrno = EEXIST;
116 return NULL;
119 if (path_inode == NULL)
121 char *dirname, *name;
122 struct vfs_s_entry *ent;
123 struct vfs_s_inode *dir;
125 dirname = g_path_get_dirname (path_super);
126 name = g_path_get_basename (path_super);
127 dir = vfs_s_find_inode (path_element->class, super, dirname, LINK_FOLLOW, FL_DIR);
128 if (dir == NULL)
130 g_free (dirname);
131 g_free (name);
132 return NULL;
134 ent = vfs_s_generate_entry (path_element->class, name, dir, 0755);
135 path_inode = ent->ino;
136 vfs_s_insert_entry (path_element->class, dir, ent);
137 g_free (dirname);
138 g_free (name);
139 is_changed = TRUE;
142 if (S_ISDIR (path_inode->st.st_mode))
144 path_element->class->verrno = EISDIR;
145 return NULL;
148 file_handler = g_new0 (vfs_file_handler_t, 1);
149 file_handler->pos = 0;
150 file_handler->ino = path_inode;
151 file_handler->handle = -1;
152 file_handler->changed = is_changed;
153 file_handler->linear = LS_NOT_LINEAR;
154 file_handler->data = NULL;
156 if (!sftpfs_open_file (file_handler, flags, mode, &mcerror))
158 mc_error_message (&mcerror, NULL);
159 g_free (file_handler);
160 return NULL;
163 vfs_rmstamp (path_element->class, (vfsid) super);
164 super->fd_usage++;
165 file_handler->ino->st.st_nlink++;
166 return file_handler;
169 /* --------------------------------------------------------------------------------------------- */
171 * Callback for opening directory.
173 * @param vpath path to directory
174 * @return directory data handler if success, NULL otherwise
177 static void *
178 sftpfs_cb_opendir (const vfs_path_t * vpath)
180 GError *mcerror = NULL;
181 void *ret_value;
183 /* reset interrupt flag */
184 tty_got_interrupt ();
186 ret_value = sftpfs_opendir (vpath, &mcerror);
187 mc_error_message (&mcerror, NULL);
188 return ret_value;
191 /* --------------------------------------------------------------------------------------------- */
193 * Callback for reading directory entry.
195 * @param data directory data handler
196 * @return information about direntry if success, NULL otherwise
199 static void *
200 sftpfs_cb_readdir (void *data)
202 GError *mcerror = NULL;
203 union vfs_dirent *sftpfs_dirent;
205 if (tty_got_interrupt ())
207 tty_disable_interrupt_key ();
208 return NULL;
211 sftpfs_dirent = sftpfs_readdir (data, &mcerror);
212 if (!mc_error_message (&mcerror, NULL))
214 if (sftpfs_dirent != NULL)
215 vfs_print_message (_("sftp: (Ctrl-G break) Listing... %s"), sftpfs_dirent->dent.d_name);
216 else
217 vfs_print_message ("%s", _("sftp: Listing done."));
220 return sftpfs_dirent;
223 /* --------------------------------------------------------------------------------------------- */
225 * Callback for closing directory.
227 * @param data directory data handler
228 * @return 0 if success, negative value otherwise
231 static int
232 sftpfs_cb_closedir (void *data)
234 int rc;
235 GError *mcerror = NULL;
237 rc = sftpfs_closedir (data, &mcerror);
238 mc_error_message (&mcerror, NULL);
239 return rc;
242 /* --------------------------------------------------------------------------------------------- */
244 * Callback for lstat VFS-function.
246 * @param vpath path to file or directory
247 * @param buf buffer for store stat-info
248 * @return 0 if success, negative value otherwise
251 static int
252 sftpfs_cb_lstat (const vfs_path_t * vpath, struct stat *buf)
254 int rc;
255 GError *mcerror = NULL;
257 rc = sftpfs_lstat (vpath, buf, &mcerror);
258 mc_error_message (&mcerror, NULL);
259 return rc;
262 /* --------------------------------------------------------------------------------------------- */
264 * Callback for stat VFS-function.
266 * @param vpath path to file or directory
267 * @param buf buffer for store stat-info
268 * @return 0 if success, negative value otherwise
271 static int
272 sftpfs_cb_stat (const vfs_path_t * vpath, struct stat *buf)
274 int rc;
275 GError *mcerror = NULL;
277 rc = sftpfs_stat (vpath, buf, &mcerror);
278 mc_error_message (&mcerror, NULL);
279 return rc;
282 /* --------------------------------------------------------------------------------------------- */
284 * Callback for fstat VFS-function.
286 * @param data file data handler
287 * @param buf buffer for store stat-info
288 * @return 0 if success, negative value otherwise
291 static int
292 sftpfs_cb_fstat (void *data, struct stat *buf)
294 int rc;
295 GError *mcerror = NULL;
297 rc = sftpfs_fstat (data, buf, &mcerror);
298 mc_error_message (&mcerror, NULL);
299 return rc;
302 /* --------------------------------------------------------------------------------------------- */
304 * Callback for readlink VFS-function.
306 * @param vpath path to file or directory
307 * @param buf buffer for store stat-info
308 * @param size buffer size
309 * @return 0 if success, negative value otherwise
312 static int
313 sftpfs_cb_readlink (const vfs_path_t * vpath, char *buf, size_t size)
315 int rc;
316 GError *mcerror = NULL;
318 rc = sftpfs_readlink (vpath, buf, size, &mcerror);
319 mc_error_message (&mcerror, NULL);
320 return rc;
323 /* --------------------------------------------------------------------------------------------- */
325 * Callback for utime VFS-function.
327 * @param vpath path to file or directory
328 * @param times access and modification time to set
329 * @return 0 if success, negative value otherwise
332 static int
333 sftpfs_cb_utime (const vfs_path_t * vpath, mc_timesbuf_t * times)
335 int rc;
336 GError *mcerror = NULL;
337 #ifdef HAVE_UTIMENSAT
338 time_t atime = (*times)[0].tv_sec;
339 time_t mtime = (*times)[1].tv_sec;
340 #else
341 time_t atime = times->actime;
342 time_t mtime = times->modtime;
343 #endif
345 rc = sftpfs_utime (vpath, atime, mtime, &mcerror);
346 mc_error_message (&mcerror, NULL);
347 return rc;
350 /* --------------------------------------------------------------------------------------------- */
352 * Callback for symlink VFS-function.
354 * @param vpath1 path to file or directory
355 * @param vpath2 path to symlink
356 * @return 0 if success, negative value otherwise
359 static int
360 sftpfs_cb_symlink (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
362 int rc;
363 GError *mcerror = NULL;
365 rc = sftpfs_symlink (vpath1, vpath2, &mcerror);
366 mc_error_message (&mcerror, NULL);
367 return rc;
370 /* --------------------------------------------------------------------------------------------- */
372 * Callback for symlink VFS-function.
374 * @param vpath unused
375 * @param mode unused
376 * @param dev unused
377 * @return always 0
380 static int
381 sftpfs_cb_mknod (const vfs_path_t * vpath, mode_t mode, dev_t dev)
383 (void) vpath;
384 (void) mode;
385 (void) dev;
387 return 0;
390 /* --------------------------------------------------------------------------------------------- */
392 * Callback for link VFS-function.
394 * @param vpath1 unused
395 * @param vpath2 unused
396 * @return always 0
399 static int
400 sftpfs_cb_link (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
402 (void) vpath1;
403 (void) vpath2;
405 return 0;
408 /* --------------------------------------------------------------------------------------------- */
410 * Callback for chown VFS-function.
412 * @param vpath unused
413 * @param owner unused
414 * @param group unused
415 * @return always 0
418 static int
419 sftpfs_cb_chown (const vfs_path_t * vpath, uid_t owner, gid_t group)
421 (void) vpath;
422 (void) owner;
423 (void) group;
425 return 0;
428 /* --------------------------------------------------------------------------------------------- */
430 * Callback for reading file content.
432 * @param data file data handler
433 * @param buffer buffer for data
434 * @param count data size
435 * @return 0 if success, negative value otherwise
438 static ssize_t
439 sftpfs_cb_read (void *data, char *buffer, size_t count)
441 int rc;
442 GError *mcerror = NULL;
443 vfs_file_handler_t *fh = (vfs_file_handler_t *) data;
445 if (tty_got_interrupt ())
447 tty_disable_interrupt_key ();
448 return 0;
451 rc = sftpfs_read_file (fh, buffer, count, &mcerror);
452 mc_error_message (&mcerror, NULL);
453 return rc;
456 /* --------------------------------------------------------------------------------------------- */
458 * Callback for writing file content.
460 * @param data file data handler
461 * @param buf buffer for data
462 * @param count data size
463 * @return 0 if success, negative value otherwise
466 static ssize_t
467 sftpfs_cb_write (void *data, const char *buf, size_t nbyte)
469 int rc;
470 GError *mcerror = NULL;
471 vfs_file_handler_t *fh = (vfs_file_handler_t *) data;
473 rc = sftpfs_write_file (fh, buf, nbyte, &mcerror);
474 mc_error_message (&mcerror, NULL);
475 return rc;
478 /* --------------------------------------------------------------------------------------------- */
480 * Callback for close file.
482 * @param data file data handler
483 * @return 0 if success, negative value otherwise
486 static int
487 sftpfs_cb_close (void *data)
489 int rc;
490 GError *mcerror = NULL;
491 struct vfs_s_super *super;
492 vfs_file_handler_t *file_handler = (vfs_file_handler_t *) data;
494 super = file_handler->ino->super;
496 super->fd_usage--;
497 if (super->fd_usage == 0)
498 vfs_stamp_create (&sftpfs_class, super);
500 rc = sftpfs_close_file (file_handler, &mcerror);
501 mc_error_message (&mcerror, NULL);
503 if (file_handler->handle != -1)
504 close (file_handler->handle);
506 vfs_s_free_inode (&sftpfs_class, file_handler->ino);
507 g_free (file_handler);
509 return rc;
512 /* --------------------------------------------------------------------------------------------- */
514 * Callback for chmod VFS-function.
516 * @param vpath path to file or directory
517 * @param mode mode (see man 2 open)
518 * @return 0 if success, negative value otherwise
521 static int
522 sftpfs_cb_chmod (const vfs_path_t * vpath, mode_t mode)
524 int rc;
525 GError *mcerror = NULL;
527 rc = sftpfs_chmod (vpath, mode, &mcerror);
528 mc_error_message (&mcerror, NULL);
529 return rc;
532 /* --------------------------------------------------------------------------------------------- */
534 * Callback for mkdir VFS-function.
536 * @param vpath path directory
537 * @param mode mode (see man 2 open)
538 * @return 0 if success, negative value otherwise
541 static int
542 sftpfs_cb_mkdir (const vfs_path_t * vpath, mode_t mode)
544 int rc;
545 GError *mcerror = NULL;
547 rc = sftpfs_mkdir (vpath, mode, &mcerror);
548 mc_error_message (&mcerror, NULL);
549 return rc;
552 /* --------------------------------------------------------------------------------------------- */
554 * Callback for rmdir VFS-function.
556 * @param vpath path directory
557 * @return 0 if success, negative value otherwise
560 static int
561 sftpfs_cb_rmdir (const vfs_path_t * vpath)
563 int rc;
564 GError *mcerror = NULL;
566 rc = sftpfs_rmdir (vpath, &mcerror);
567 mc_error_message (&mcerror, NULL);
568 return rc;
571 /* --------------------------------------------------------------------------------------------- */
573 * Callback for lseek VFS-function.
575 * @param data file data handler
576 * @param offset file offset
577 * @param whence method of seek (at begin, at current, at end)
578 * @return 0 if success, negative value otherwise
581 static off_t
582 sftpfs_cb_lseek (void *data, off_t offset, int whence)
584 off_t ret_offset;
585 vfs_file_handler_t *file_handler = (vfs_file_handler_t *) data;
586 GError *mcerror = NULL;
588 ret_offset = sftpfs_lseek (file_handler, offset, whence, &mcerror);
589 mc_error_message (&mcerror, NULL);
590 return ret_offset;
593 /* --------------------------------------------------------------------------------------------- */
595 * Callback for unlink VFS-function.
597 * @param vpath path to file or directory
598 * @return 0 if success, negative value otherwise
601 static int
602 sftpfs_cb_unlink (const vfs_path_t * vpath)
604 int rc;
605 GError *mcerror = NULL;
607 rc = sftpfs_unlink (vpath, &mcerror);
608 mc_error_message (&mcerror, NULL);
609 return rc;
612 /* --------------------------------------------------------------------------------------------- */
614 * Callback for rename VFS-function.
616 * @param vpath1 path to source file or directory
617 * @param vpath2 path to destination file or directory
618 * @return 0 if success, negative value otherwise
621 static int
622 sftpfs_cb_rename (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
624 int rc;
625 GError *mcerror = NULL;
627 rc = sftpfs_rename (vpath1, vpath2, &mcerror);
628 mc_error_message (&mcerror, NULL);
629 return rc;
632 /* --------------------------------------------------------------------------------------------- */
634 * Callback for errno VFS-function.
636 * @param me unused
637 * @return value of errno global variable
640 static int
641 sftpfs_cb_errno (struct vfs_class *me)
643 (void) me;
644 return errno;
647 /* --------------------------------------------------------------------------------------------- */
649 * Callback for fill_names VFS function.
650 * Add SFTP connections to the 'Active VFS connections' list
652 * @param me unused
653 * @param func callback function for adding SFTP-connection to list of active connections
656 static void
657 sftpfs_cb_fill_names (struct vfs_class *me, fill_names_f func)
659 GList *iter;
661 (void) me;
663 for (iter = sftpfs_subclass.supers; iter != NULL; iter = g_list_next (iter))
665 const struct vfs_s_super *super = (const struct vfs_s_super *) iter->data;
666 char *name;
668 name = vfs_path_element_build_pretty_path_str (super->path_element);
670 func (name);
671 g_free (name);
675 /* --------------------------------------------------------------------------------------------- */
676 /*** public functions ****************************************************************************/
677 /* --------------------------------------------------------------------------------------------- */
679 * Initialization of VFS class structure.
681 * @return the VFS class structure.
684 void
685 sftpfs_init_class (void)
687 memset (&sftpfs_class, 0, sizeof (sftpfs_class));
688 sftpfs_class.name = "sftpfs";
689 sftpfs_class.prefix = "sftp";
690 sftpfs_class.flags = VFSF_NOLINKS;
693 /* --------------------------------------------------------------------------------------------- */
695 * Initialization of VFS class callbacks.
698 void
699 sftpfs_init_class_callbacks (void)
701 sftpfs_class.init = sftpfs_cb_init;
702 sftpfs_class.done = sftpfs_cb_done;
704 sftpfs_class.fill_names = sftpfs_cb_fill_names;
706 sftpfs_class.opendir = sftpfs_cb_opendir;
707 sftpfs_class.readdir = sftpfs_cb_readdir;
708 sftpfs_class.closedir = sftpfs_cb_closedir;
709 sftpfs_class.mkdir = sftpfs_cb_mkdir;
710 sftpfs_class.rmdir = sftpfs_cb_rmdir;
712 sftpfs_class.stat = sftpfs_cb_stat;
713 sftpfs_class.lstat = sftpfs_cb_lstat;
714 sftpfs_class.fstat = sftpfs_cb_fstat;
715 sftpfs_class.readlink = sftpfs_cb_readlink;
716 sftpfs_class.symlink = sftpfs_cb_symlink;
717 sftpfs_class.link = sftpfs_cb_link;
718 sftpfs_class.utime = sftpfs_cb_utime;
719 sftpfs_class.mknod = sftpfs_cb_mknod;
720 sftpfs_class.chown = sftpfs_cb_chown;
721 sftpfs_class.chmod = sftpfs_cb_chmod;
723 sftpfs_class.open = sftpfs_cb_open;
724 sftpfs_class.read = sftpfs_cb_read;
725 sftpfs_class.write = sftpfs_cb_write;
726 sftpfs_class.close = sftpfs_cb_close;
727 sftpfs_class.lseek = sftpfs_cb_lseek;
728 sftpfs_class.unlink = sftpfs_cb_unlink;
729 sftpfs_class.rename = sftpfs_cb_rename;
730 sftpfs_class.ferrno = sftpfs_cb_errno;
733 /* --------------------------------------------------------------------------------------------- */