1 /* Virtual File System: SFTP file system.
2    The VFS class functions
3 
4    Copyright (C) 2011-2021
5    Free Software Foundation, Inc.
6 
7    Written by:
8    Ilia Maslakov <il.smind@gmail.com>, 2011
9    Slava Zanko <slavazanko@gmail.com>, 2011, 2012
10 
11    This file is part of the Midnight Commander.
12 
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.
17 
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.
22 
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/>.
25  */
26 
27 #include <config.h>
28 #include <errno.h>
29 
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 () */
34 
35 #include "internal.h"
36 
37 /*** global variables ****************************************************************************/
38 
39 /*** file scope macro definitions ****************************************************************/
40 
41 /*** file scope type declarations ****************************************************************/
42 
43 /*** file scope variables ************************************************************************/
44 
45 /*** file scope functions ************************************************************************/
46 /* --------------------------------------------------------------------------------------------- */
47 /**
48  * Callback for VFS-class init action.
49  *
50  * @param me structure of VFS class
51  */
52 
53 static int
sftpfs_cb_init(struct vfs_class * me)54 sftpfs_cb_init (struct vfs_class *me)
55 {
56     (void) me;
57 
58     if (libssh2_init (0) != 0)
59         return 0;
60 
61     sftpfs_filename_buffer = g_string_new ("");
62     sftpfs_init_config_variables_patterns ();
63     return 1;
64 }
65 
66 /* --------------------------------------------------------------------------------------------- */
67 /**
68  * Callback for VFS-class deinit action.
69  *
70  * @param me structure of VFS class
71  */
72 
73 static void
sftpfs_cb_done(struct vfs_class * me)74 sftpfs_cb_done (struct vfs_class *me)
75 {
76     (void) me;
77 
78     sftpfs_deinit_config_variables_patterns ();
79     g_string_free (sftpfs_filename_buffer, TRUE);
80     libssh2_exit ();
81 }
82 
83 /* --------------------------------------------------------------------------------------------- */
84 /**
85  * Callback for opening file.
86  *
87  * @param vpath path to file
88  * @param flags flags (see man 2 open)
89  * @param mode  mode (see man 2 open)
90  * @return file data handler if success, NULL otherwise
91  */
92 
93 static void *
sftpfs_cb_open(const vfs_path_t * vpath,int flags,mode_t mode)94 sftpfs_cb_open (const vfs_path_t * vpath, int flags, mode_t mode)
95 {
96     vfs_file_handler_t *fh;
97     const vfs_path_element_t *path_element;
98     struct vfs_s_super *super;
99     const char *path_super;
100     struct vfs_s_inode *path_inode;
101     GError *mcerror = NULL;
102     gboolean is_changed = FALSE;
103 
104     path_element = vfs_path_get_by_index (vpath, -1);
105 
106     path_super = vfs_s_get_path (vpath, &super, 0);
107     if (path_super == NULL)
108         return NULL;
109 
110     path_inode = vfs_s_find_inode (path_element->class, super, path_super, LINK_FOLLOW, FL_NONE);
111     if (path_inode != NULL && ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)))
112     {
113         path_element->class->verrno = EEXIST;
114         return NULL;
115     }
116 
117     if (path_inode == NULL)
118     {
119         char *dirname, *name;
120         struct vfs_s_entry *ent;
121         struct vfs_s_inode *dir;
122 
123         dirname = g_path_get_dirname (path_super);
124         name = g_path_get_basename (path_super);
125         dir = vfs_s_find_inode (path_element->class, super, dirname, LINK_FOLLOW, FL_DIR);
126         if (dir == NULL)
127         {
128             g_free (dirname);
129             g_free (name);
130             return NULL;
131         }
132         ent = vfs_s_generate_entry (path_element->class, name, dir, 0755);
133         path_inode = ent->ino;
134         vfs_s_insert_entry (path_element->class, dir, ent);
135         g_free (dirname);
136         g_free (name);
137         is_changed = TRUE;
138     }
139 
140     if (S_ISDIR (path_inode->st.st_mode))
141     {
142         path_element->class->verrno = EISDIR;
143         return NULL;
144     }
145 
146     fh = sftpfs_fh_new (path_inode, is_changed);
147 
148     if (!sftpfs_open_file (fh, flags, mode, &mcerror))
149     {
150         mc_error_message (&mcerror, NULL);
151         g_free (fh);
152         return NULL;
153     }
154 
155     vfs_rmstamp (path_element->class, (vfsid) super);
156     super->fd_usage++;
157     fh->ino->st.st_nlink++;
158     return fh;
159 }
160 
161 /* --------------------------------------------------------------------------------------------- */
162 /**
163  * Callback for opening directory.
164  *
165  * @param vpath path to directory
166  * @return directory data handler if success, NULL otherwise
167  */
168 
169 static void *
sftpfs_cb_opendir(const vfs_path_t * vpath)170 sftpfs_cb_opendir (const vfs_path_t * vpath)
171 {
172     GError *mcerror = NULL;
173     void *ret_value;
174 
175     /* reset interrupt flag */
176     tty_got_interrupt ();
177 
178     ret_value = sftpfs_opendir (vpath, &mcerror);
179     mc_error_message (&mcerror, NULL);
180     return ret_value;
181 }
182 
183 /* --------------------------------------------------------------------------------------------- */
184 /**
185  * Callback for reading directory entry.
186  *
187  * @param data directory data handler
188  * @return information about direntry if success, NULL otherwise
189  */
190 
191 static struct vfs_dirent *
sftpfs_cb_readdir(void * data)192 sftpfs_cb_readdir (void *data)
193 {
194     GError *mcerror = NULL;
195     struct vfs_dirent *sftpfs_dirent;
196 
197     if (tty_got_interrupt ())
198     {
199         tty_disable_interrupt_key ();
200         return NULL;
201     }
202 
203     sftpfs_dirent = sftpfs_readdir (data, &mcerror);
204     if (!mc_error_message (&mcerror, NULL))
205     {
206         if (sftpfs_dirent != NULL)
207             vfs_print_message (_("sftp: (Ctrl-G break) Listing... %s"), sftpfs_dirent->d_name);
208         else
209             vfs_print_message ("%s", _("sftp: Listing done."));
210     }
211 
212     return sftpfs_dirent;
213 }
214 
215 /* --------------------------------------------------------------------------------------------- */
216 /**
217  * Callback for closing directory.
218  *
219  * @param data directory data handler
220  * @return 0 if success, negative value otherwise
221  */
222 
223 static int
sftpfs_cb_closedir(void * data)224 sftpfs_cb_closedir (void *data)
225 {
226     int rc;
227     GError *mcerror = NULL;
228 
229     rc = sftpfs_closedir (data, &mcerror);
230     mc_error_message (&mcerror, NULL);
231     return rc;
232 }
233 
234 /* --------------------------------------------------------------------------------------------- */
235 /**
236  * Callback for lstat VFS-function.
237  *
238  * @param vpath path to file or directory
239  * @param buf   buffer for store stat-info
240  * @return 0 if success, negative value otherwise
241  */
242 
243 static int
sftpfs_cb_lstat(const vfs_path_t * vpath,struct stat * buf)244 sftpfs_cb_lstat (const vfs_path_t * vpath, struct stat *buf)
245 {
246     int rc;
247     GError *mcerror = NULL;
248 
249     rc = sftpfs_lstat (vpath, buf, &mcerror);
250     mc_error_message (&mcerror, NULL);
251     return rc;
252 }
253 
254 /* --------------------------------------------------------------------------------------------- */
255 /**
256  * Callback for stat VFS-function.
257  *
258  * @param vpath path to file or directory
259  * @param buf   buffer for store stat-info
260  * @return 0 if success, negative value otherwise
261  */
262 
263 static int
sftpfs_cb_stat(const vfs_path_t * vpath,struct stat * buf)264 sftpfs_cb_stat (const vfs_path_t * vpath, struct stat *buf)
265 {
266     int rc;
267     GError *mcerror = NULL;
268 
269     rc = sftpfs_stat (vpath, buf, &mcerror);
270     mc_error_message (&mcerror, NULL);
271     return rc;
272 }
273 
274 /* --------------------------------------------------------------------------------------------- */
275 /**
276  * Callback for fstat VFS-function.
277  *
278  * @param data file data handler
279  * @param buf  buffer for store stat-info
280  * @return 0 if success, negative value otherwise
281  */
282 
283 static int
sftpfs_cb_fstat(void * data,struct stat * buf)284 sftpfs_cb_fstat (void *data, struct stat *buf)
285 {
286     int rc;
287     GError *mcerror = NULL;
288 
289     rc = sftpfs_fstat (data, buf, &mcerror);
290     mc_error_message (&mcerror, NULL);
291     return rc;
292 }
293 
294 /* --------------------------------------------------------------------------------------------- */
295 /**
296  * Callback for readlink VFS-function.
297  *
298  * @param vpath path to file or directory
299  * @param buf   buffer for store stat-info
300  * @param size  buffer size
301  * @return 0 if success, negative value otherwise
302  */
303 
304 static int
sftpfs_cb_readlink(const vfs_path_t * vpath,char * buf,size_t size)305 sftpfs_cb_readlink (const vfs_path_t * vpath, char *buf, size_t size)
306 {
307     int rc;
308     GError *mcerror = NULL;
309 
310     rc = sftpfs_readlink (vpath, buf, size, &mcerror);
311     mc_error_message (&mcerror, NULL);
312     return rc;
313 }
314 
315 /* --------------------------------------------------------------------------------------------- */
316 /**
317  * Callback for utime VFS-function.
318  *
319  * @param vpath path to file or directory
320  * @param times access and modification time to set
321  * @return 0 if success, negative value otherwise
322  */
323 
324 static int
sftpfs_cb_utime(const vfs_path_t * vpath,mc_timesbuf_t * times)325 sftpfs_cb_utime (const vfs_path_t * vpath, mc_timesbuf_t * times)
326 {
327     int rc;
328     GError *mcerror = NULL;
329 #ifdef HAVE_UTIMENSAT
330     time_t atime = (*times)[0].tv_sec;
331     time_t mtime = (*times)[1].tv_sec;
332 #else
333     time_t atime = times->actime;
334     time_t mtime = times->modtime;
335 #endif
336 
337     rc = sftpfs_utime (vpath, atime, mtime, &mcerror);
338     mc_error_message (&mcerror, NULL);
339     return rc;
340 }
341 
342 /* --------------------------------------------------------------------------------------------- */
343 /**
344  * Callback for symlink VFS-function.
345  *
346  * @param vpath1 path to file or directory
347  * @param vpath2 path to symlink
348  * @return 0 if success, negative value otherwise
349  */
350 
351 static int
sftpfs_cb_symlink(const vfs_path_t * vpath1,const vfs_path_t * vpath2)352 sftpfs_cb_symlink (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
353 {
354     int rc;
355     GError *mcerror = NULL;
356 
357     rc = sftpfs_symlink (vpath1, vpath2, &mcerror);
358     mc_error_message (&mcerror, NULL);
359     return rc;
360 }
361 
362 /* --------------------------------------------------------------------------------------------- */
363 /**
364  * Callback for symlink VFS-function.
365  *
366  * @param vpath unused
367  * @param mode  unused
368  * @param dev   unused
369  * @return always 0
370  */
371 
372 static int
sftpfs_cb_mknod(const vfs_path_t * vpath,mode_t mode,dev_t dev)373 sftpfs_cb_mknod (const vfs_path_t * vpath, mode_t mode, dev_t dev)
374 {
375     (void) vpath;
376     (void) mode;
377     (void) dev;
378 
379     return 0;
380 }
381 
382 /* --------------------------------------------------------------------------------------------- */
383 /**
384  * Callback for link VFS-function.
385  *
386  * @param vpath1 unused
387  * @param vpath2 unused
388  * @return always 0
389  */
390 
391 static int
sftpfs_cb_link(const vfs_path_t * vpath1,const vfs_path_t * vpath2)392 sftpfs_cb_link (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
393 {
394     (void) vpath1;
395     (void) vpath2;
396 
397     return 0;
398 }
399 
400 /* --------------------------------------------------------------------------------------------- */
401 /**
402  * Callback for chown VFS-function.
403  *
404  * @param vpath unused
405  * @param owner unused
406  * @param group unused
407  * @return always 0
408  */
409 
410 static int
sftpfs_cb_chown(const vfs_path_t * vpath,uid_t owner,gid_t group)411 sftpfs_cb_chown (const vfs_path_t * vpath, uid_t owner, gid_t group)
412 {
413     (void) vpath;
414     (void) owner;
415     (void) group;
416 
417     return 0;
418 }
419 
420 /* --------------------------------------------------------------------------------------------- */
421 /**
422  * Callback for reading file content.
423  *
424  * @param data   file data handler
425  * @param buffer buffer for data
426  * @param count  data size
427  * @return 0 if success, negative value otherwise
428  */
429 
430 static ssize_t
sftpfs_cb_read(void * data,char * buffer,size_t count)431 sftpfs_cb_read (void *data, char *buffer, size_t count)
432 {
433     int rc;
434     GError *mcerror = NULL;
435     vfs_file_handler_t *fh = VFS_FILE_HANDLER (data);
436 
437     if (tty_got_interrupt ())
438     {
439         tty_disable_interrupt_key ();
440         return 0;
441     }
442 
443     rc = sftpfs_read_file (fh, buffer, count, &mcerror);
444     mc_error_message (&mcerror, NULL);
445     return rc;
446 }
447 
448 /* --------------------------------------------------------------------------------------------- */
449 /**
450  * Callback for writing file content.
451  *
452  * @param data  file data handler
453  * @param buf   buffer for data
454  * @param count data size
455  * @return 0 if success, negative value otherwise
456  */
457 
458 static ssize_t
sftpfs_cb_write(void * data,const char * buf,size_t nbyte)459 sftpfs_cb_write (void *data, const char *buf, size_t nbyte)
460 {
461     int rc;
462     GError *mcerror = NULL;
463     vfs_file_handler_t *fh = VFS_FILE_HANDLER (data);
464 
465     rc = sftpfs_write_file (fh, buf, nbyte, &mcerror);
466     mc_error_message (&mcerror, NULL);
467     return rc;
468 }
469 
470 /* --------------------------------------------------------------------------------------------- */
471 /**
472  * Callback for close file.
473  *
474  * @param data file data handler
475  * @return 0 if success, negative value otherwise
476  */
477 
478 static int
sftpfs_cb_close(void * data)479 sftpfs_cb_close (void *data)
480 {
481     int rc;
482     GError *mcerror = NULL;
483     struct vfs_s_super *super = VFS_FILE_HANDLER_SUPER (data);
484     vfs_file_handler_t *fh = VFS_FILE_HANDLER (data);
485 
486     super->fd_usage--;
487     if (super->fd_usage == 0)
488         vfs_stamp_create (sftpfs_class, super);
489 
490     rc = sftpfs_close_file (fh, &mcerror);
491     mc_error_message (&mcerror, NULL);
492 
493     if (fh->handle != -1)
494         close (fh->handle);
495 
496     vfs_s_free_inode (sftpfs_class, fh->ino);
497 
498     return rc;
499 }
500 
501 /* --------------------------------------------------------------------------------------------- */
502 /**
503  * Callback for chmod VFS-function.
504  *
505  * @param vpath path to file or directory
506  * @param mode  mode (see man 2 open)
507  * @return 0 if success, negative value otherwise
508  */
509 
510 static int
sftpfs_cb_chmod(const vfs_path_t * vpath,mode_t mode)511 sftpfs_cb_chmod (const vfs_path_t * vpath, mode_t mode)
512 {
513     int rc;
514     GError *mcerror = NULL;
515 
516     rc = sftpfs_chmod (vpath, mode, &mcerror);
517     mc_error_message (&mcerror, NULL);
518     return rc;
519 }
520 
521 /* --------------------------------------------------------------------------------------------- */
522 /**
523  * Callback for mkdir VFS-function.
524  *
525  * @param vpath path directory
526  * @param mode  mode (see man 2 open)
527  * @return 0 if success, negative value otherwise
528  */
529 
530 static int
sftpfs_cb_mkdir(const vfs_path_t * vpath,mode_t mode)531 sftpfs_cb_mkdir (const vfs_path_t * vpath, mode_t mode)
532 {
533     int rc;
534     GError *mcerror = NULL;
535 
536     rc = sftpfs_mkdir (vpath, mode, &mcerror);
537     mc_error_message (&mcerror, NULL);
538     return rc;
539 }
540 
541 /* --------------------------------------------------------------------------------------------- */
542 /**
543  * Callback for rmdir VFS-function.
544  *
545  * @param vpath path directory
546  * @return 0 if success, negative value otherwise
547  */
548 
549 static int
sftpfs_cb_rmdir(const vfs_path_t * vpath)550 sftpfs_cb_rmdir (const vfs_path_t * vpath)
551 {
552     int rc;
553     GError *mcerror = NULL;
554 
555     rc = sftpfs_rmdir (vpath, &mcerror);
556     mc_error_message (&mcerror, NULL);
557     return rc;
558 }
559 
560 /* --------------------------------------------------------------------------------------------- */
561 /**
562  * Callback for lseek VFS-function.
563  *
564  * @param data   file data handler
565  * @param offset file offset
566  * @param whence method of seek (at begin, at current, at end)
567  * @return 0 if success, negative value otherwise
568  */
569 
570 static off_t
sftpfs_cb_lseek(void * data,off_t offset,int whence)571 sftpfs_cb_lseek (void *data, off_t offset, int whence)
572 {
573     off_t ret_offset;
574     vfs_file_handler_t *fh = VFS_FILE_HANDLER (data);
575     GError *mcerror = NULL;
576 
577     ret_offset = sftpfs_lseek (fh, offset, whence, &mcerror);
578     mc_error_message (&mcerror, NULL);
579     return ret_offset;
580 }
581 
582 /* --------------------------------------------------------------------------------------------- */
583 /**
584  * Callback for unlink VFS-function.
585  *
586  * @param vpath path to file or directory
587  * @return 0 if success, negative value otherwise
588  */
589 
590 static int
sftpfs_cb_unlink(const vfs_path_t * vpath)591 sftpfs_cb_unlink (const vfs_path_t * vpath)
592 {
593     int rc;
594     GError *mcerror = NULL;
595 
596     rc = sftpfs_unlink (vpath, &mcerror);
597     mc_error_message (&mcerror, NULL);
598     return rc;
599 }
600 
601 /* --------------------------------------------------------------------------------------------- */
602 /**
603  * Callback for rename VFS-function.
604  *
605  * @param vpath1 path to source file or directory
606  * @param vpath2 path to destination file or directory
607  * @return 0 if success, negative value otherwise
608  */
609 
610 static int
sftpfs_cb_rename(const vfs_path_t * vpath1,const vfs_path_t * vpath2)611 sftpfs_cb_rename (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
612 {
613     int rc;
614     GError *mcerror = NULL;
615 
616     rc = sftpfs_rename (vpath1, vpath2, &mcerror);
617     mc_error_message (&mcerror, NULL);
618     return rc;
619 }
620 
621 /* --------------------------------------------------------------------------------------------- */
622 /**
623  * Callback for errno VFS-function.
624  *
625  * @param me unused
626  * @return value of errno global variable
627  */
628 
629 static int
sftpfs_cb_errno(struct vfs_class * me)630 sftpfs_cb_errno (struct vfs_class *me)
631 {
632     (void) me;
633     return errno;
634 }
635 
636 /* --------------------------------------------------------------------------------------------- */
637 /**
638  * Callback for fill_names VFS function.
639  * Add SFTP connections to the 'Active VFS connections'  list
640  *
641  * @param me   unused
642  * @param func callback function for adding SFTP-connection to list of active connections
643  */
644 
645 static void
sftpfs_cb_fill_names(struct vfs_class * me,fill_names_f func)646 sftpfs_cb_fill_names (struct vfs_class *me, fill_names_f func)
647 {
648     GList *iter;
649 
650     (void) me;
651 
652     for (iter = sftpfs_subclass.supers; iter != NULL; iter = g_list_next (iter))
653     {
654         const struct vfs_s_super *super = (const struct vfs_s_super *) iter->data;
655         char *name;
656 
657         name = vfs_path_element_build_pretty_path_str (super->path_element);
658 
659         func (name);
660         g_free (name);
661     }
662 }
663 
664 /* --------------------------------------------------------------------------------------------- */
665 /*** public functions ****************************************************************************/
666 /* --------------------------------------------------------------------------------------------- */
667 /**
668  * Initialization of VFS class structure.
669  *
670  * @return the VFS class structure.
671  */
672 
673 void
sftpfs_init_class(void)674 sftpfs_init_class (void)
675 {
676     sftpfs_class->init = sftpfs_cb_init;
677     sftpfs_class->done = sftpfs_cb_done;
678 
679     sftpfs_class->fill_names = sftpfs_cb_fill_names;
680 
681     sftpfs_class->opendir = sftpfs_cb_opendir;
682     sftpfs_class->readdir = sftpfs_cb_readdir;
683     sftpfs_class->closedir = sftpfs_cb_closedir;
684     sftpfs_class->mkdir = sftpfs_cb_mkdir;
685     sftpfs_class->rmdir = sftpfs_cb_rmdir;
686 
687     sftpfs_class->stat = sftpfs_cb_stat;
688     sftpfs_class->lstat = sftpfs_cb_lstat;
689     sftpfs_class->fstat = sftpfs_cb_fstat;
690     sftpfs_class->readlink = sftpfs_cb_readlink;
691     sftpfs_class->symlink = sftpfs_cb_symlink;
692     sftpfs_class->link = sftpfs_cb_link;
693     sftpfs_class->utime = sftpfs_cb_utime;
694     sftpfs_class->mknod = sftpfs_cb_mknod;
695     sftpfs_class->chown = sftpfs_cb_chown;
696     sftpfs_class->chmod = sftpfs_cb_chmod;
697 
698     sftpfs_class->open = sftpfs_cb_open;
699     sftpfs_class->read = sftpfs_cb_read;
700     sftpfs_class->write = sftpfs_cb_write;
701     sftpfs_class->close = sftpfs_cb_close;
702     sftpfs_class->lseek = sftpfs_cb_lseek;
703     sftpfs_class->unlink = sftpfs_cb_unlink;
704     sftpfs_class->rename = sftpfs_cb_rename;
705     sftpfs_class->ferrno = sftpfs_cb_errno;
706 }
707 
708 /* --------------------------------------------------------------------------------------------- */
709