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