This source file includes following definitions.
- ftpfs_set_blksize
- ftpfs_default_stat
- ftpfs_translate_path
- ftpfs_correct_url_parameters
- ftpfs_get_reply
- ftpfs_reconnect
- G_GNUC_PRINTF
- ftpfs_new_archive
- ftpfs_free_archive
- ftpfs_changetype
- ftpfs_login_server
- ftpfs_load_no_proxy_list
- ftpfs_check_proxy
- ftpfs_get_proxy_host_and_port
- ftpfs_open_socket
- ftpfs_open_archive_int
- ftpfs_open_archive
- ftpfs_archive_same
- ftpfs_get_current_directory
- ftpfs_setup_passive_pasv
- ftpfs_setup_passive_epsv
- ftpfs_setup_passive
- ftpfs_setup_active
- ftpfs_init_data_socket
- ftpfs_initconn
- ftpfs_open_data_connection
- ftpfs_linear_abort
- resolve_symlink_without_ls_options
- resolve_symlink_with_ls_options
- resolve_symlink
- ftpfs_dir_load
- ftpfs_file_store
- ftpfs_linear_start
- ftpfs_linear_read
- ftpfs_linear_close
- ftpfs_ctl
- ftpfs_send_command
- ftpfs_stat
- ftpfs_lstat
- ftpfs_fstat
- ftpfs_chmod
- ftpfs_chown
- ftpfs_unlink
- ftpfs_is_same_dir
- ftpfs_chdir_internal
- ftpfs_rename
- ftpfs_mkdir
- ftpfs_rmdir
- ftpfs_fh_new
- ftpfs_fh_open
- ftpfs_fh_close
- ftpfs_done
- ftpfs_fill_names
- ftpfs_netrc_next
- ftpfs_netrc_bad_mode
- ftpfs_find_machine
- ftpfs_netrc_lookup
- ftpfs_init_passwd
- ftpfs_utime
- vfs_init_ftpfs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77 #include <config.h>
78 #include <stdio.h>
79 #include <stdlib.h>
80 #include <sys/types.h>
81 #include <netdb.h>
82 #include <sys/socket.h>
83 #include <netinet/in.h>
84 #ifdef HAVE_ARPA_INET_H
85 #include <arpa/inet.h>
86 #endif
87 #include <arpa/ftp.h>
88 #include <arpa/telnet.h>
89 #ifdef HAVE_SYS_PARAM_H
90 #include <sys/param.h>
91 #endif
92 #include <errno.h>
93 #include <ctype.h>
94 #include <fcntl.h>
95 #include <inttypes.h>
96
97 #include "lib/global.h"
98 #include "lib/file-entry.h"
99 #include "lib/util.h"
100 #include "lib/strutil.h"
101 #include "lib/mcconfig.h"
102
103 #include "lib/tty/tty.h"
104 #include "lib/widget.h"
105
106 #include "src/history.h"
107 #include "src/setup.h"
108
109 #include "lib/vfs/vfs.h"
110 #include "lib/vfs/utilvfs.h"
111 #include "lib/vfs/netutil.h"
112 #include "lib/vfs/xdirentry.h"
113 #include "lib/vfs/gc.h"
114
115 #include "ftpfs.h"
116
117
118
119
120 int ftpfs_retry_seconds = 30;
121
122
123 gboolean ftpfs_use_passive_connections = TRUE;
124 gboolean ftpfs_use_passive_connections_over_proxy = FALSE;
125
126
127
128
129
130
131 gboolean ftpfs_use_unix_list_options = TRUE;
132
133
134 gboolean ftpfs_first_cd_then_ls = TRUE;
135
136
137 gboolean ftpfs_use_netrc = TRUE;
138
139
140 char *ftpfs_anonymous_passwd = NULL;
141 int ftpfs_directory_timeout = 900;
142
143
144 char *ftpfs_proxy_host = NULL;
145
146
147 gboolean ftpfs_always_use_proxy = FALSE;
148
149 gboolean ftpfs_ignore_chattr_errors = TRUE;
150
151
152
153 #ifndef MAXHOSTNAMELEN
154 #define MAXHOSTNAMELEN 64
155 #endif
156
157 #define FTP_SUPER(super) ((ftp_super_t *) (super))
158 #define FTP_FILE_HANDLER(fh) ((ftp_file_handler_t *) (fh))
159 #define FH_SOCK FTP_FILE_HANDLER (fh)->sock
160
161 #ifndef INADDR_NONE
162 #define INADDR_NONE 0xffffffff
163 #endif
164
165 #define RFC_AUTODETECT 0
166 #define RFC_DARING 1
167 #define RFC_STRICT 2
168
169
170 #define NONE 0x00
171 #define WAIT_REPLY 0x01
172 #define WANT_STRING 0x02
173
174 #define FTP_COMMAND_PORT 21
175
176
177
178 #define TYPE_ASCII 0
179 #define TYPE_BINARY 1
180
181
182
183 #define TYPE_UNKNOWN -1
184
185 #define ABORT_TIMEOUT (5 * G_USEC_PER_SEC)
186
187
188 #ifndef HAVE_SOCKLEN_T
189 typedef int socklen_t;
190 #endif
191
192
193 typedef enum
194 {
195 NETRC_NONE = 0,
196 NETRC_DEFAULT,
197 NETRC_MACHINE,
198 NETRC_LOGIN,
199 NETRC_PASSWORD,
200 NETRC_PASSWD,
201 NETRC_ACCOUNT,
202 NETRC_MACDEF,
203 NETRC_UNKNOWN
204 } keyword_t;
205
206 typedef struct
207 {
208 struct vfs_s_super base;
209
210 int sock;
211
212 char *proxy;
213 gboolean failed_on_login;
214 gboolean use_passive_connection;
215 gboolean remote_is_amiga;
216 int isbinary;
217 gboolean cwd_deferred;
218
219 int strict;
220
221
222
223 gboolean ctl_connection_busy;
224 char *current_dir;
225 } ftp_super_t;
226
227 typedef struct
228 {
229 vfs_file_handler_t base;
230
231 int sock;
232 gboolean append;
233 } ftp_file_handler_t;
234
235
236
237 static char *ftpfs_get_current_directory (struct vfs_class *me, struct vfs_s_super *super);
238 static int ftpfs_chdir_internal (struct vfs_class *me, struct vfs_s_super *super,
239 const char *remote_path);
240 static int ftpfs_open_socket (struct vfs_class *me, struct vfs_s_super *super);
241 static gboolean ftpfs_login_server (struct vfs_class *me, struct vfs_s_super *super,
242 const char *netrcpass);
243 static gboolean ftpfs_netrc_lookup (const char *host, char **login, char **pass);
244
245
246
247 static int code;
248
249 static char reply_str[80];
250
251 static struct vfs_s_subclass ftpfs_subclass;
252 static struct vfs_class *vfs_ftpfs_ops = VFS_CLASS (&ftpfs_subclass);
253
254 static GSList *no_proxy = NULL;
255
256 static char buffer[BUF_MEDIUM];
257 static char *netrc = NULL;
258 static const char *netrcp;
259
260
261
262
263
264 static void
265 ftpfs_set_blksize (struct stat *s)
266 {
267 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
268
269 s->st_blksize = 64 * 1024;
270 #endif
271 }
272
273
274
275 static struct stat *
276 ftpfs_default_stat (struct vfs_class *me)
277 {
278 struct stat *s;
279
280 s = vfs_s_default_stat (me, S_IFDIR | 0755);
281 ftpfs_set_blksize (s);
282 vfs_adjust_stat (s);
283
284 return s;
285 }
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300 static char *
301 ftpfs_translate_path (struct vfs_class *me, struct vfs_s_super *super, const char *remote_path)
302 {
303 char *ret, *p;
304
305 if (!FTP_SUPER (super)->remote_is_amiga)
306 return g_strdup (remote_path);
307
308 if (me->logfile != NULL)
309 {
310 fprintf (me->logfile, "MC -- ftpfs_translate_path: %s\n", remote_path);
311 fflush (me->logfile);
312 }
313
314
315 while (IS_PATH_SEP (*remote_path))
316 remote_path++;
317
318
319 if (*remote_path == '\0')
320 return g_strdup (".");
321
322 ret = g_strdup (remote_path);
323
324
325 p = strchr (ret, ':');
326 if (p != NULL && IS_PATH_SEP (p[1]))
327 str_move (p + 1, p + 2);
328
329
330 p = strrchr (ret, PATH_SEP);
331 if ((p != NULL) && (*(p + 1) == '.') && (*(p + 2) == '\0'))
332 *p = '\0';
333
334 return ret;
335 }
336
337
338
339
340
341
342
343
344
345
346
347
348
349 static vfs_path_element_t *
350 ftpfs_correct_url_parameters (const vfs_path_element_t *velement)
351 {
352 vfs_path_element_t *path_element = vfs_path_element_clone (velement);
353
354 if (path_element->port == 0)
355 path_element->port = FTP_COMMAND_PORT;
356
357 if (path_element->user == NULL)
358 {
359
360 if (ftpfs_use_netrc)
361 ftpfs_netrc_lookup (path_element->host, &path_element->user, &path_element->password);
362 }
363 if (path_element->user == NULL)
364 path_element->user = g_strdup ("anonymous");
365
366
367 if (ftpfs_use_netrc && path_element->password == NULL)
368 {
369 char *new_user = NULL;
370 char *new_passwd = NULL;
371
372 ftpfs_netrc_lookup (path_element->host, &new_user, &new_passwd);
373
374
375 if (new_user != NULL && strcmp (path_element->user, new_user) == 0)
376 path_element->password = new_passwd;
377 else
378 g_free (new_passwd);
379
380 g_free (new_user);
381 }
382
383 return path_element;
384 }
385
386
387
388
389 static int
390 ftpfs_get_reply (struct vfs_class *me, int sock, char *string_buf, int string_len)
391 {
392 while (TRUE)
393 {
394 char answer[BUF_1K];
395
396 if (vfs_s_get_line (me, sock, answer, sizeof (answer), '\n') == 0)
397 {
398 if (string_buf != NULL)
399 *string_buf = '\0';
400 code = 421;
401 return 4;
402 }
403
404 switch (sscanf (answer, "%d", &code))
405 {
406 case 0:
407 if (string_buf != NULL)
408 g_strlcpy (string_buf, answer, string_len);
409 code = 500;
410 return 5;
411 case 1:
412 if (answer[3] == '-')
413 {
414 while (TRUE)
415 {
416 int i;
417
418 if (vfs_s_get_line (me, sock, answer, sizeof (answer), '\n') == 0)
419 {
420 if (string_buf != NULL)
421 *string_buf = '\0';
422 code = 421;
423 return 4;
424 }
425 if ((sscanf (answer, "%d", &i) > 0) && (code == i) && (answer[3] == ' '))
426 break;
427 }
428 }
429 if (string_buf != NULL)
430 g_strlcpy (string_buf, answer, string_len);
431 return code / 100;
432 default:
433 break;
434 }
435 }
436 }
437
438
439
440 static gboolean
441 ftpfs_reconnect (struct vfs_class *me, struct vfs_s_super *super)
442 {
443 ftp_super_t *ftp_super = FTP_SUPER (super);
444 int sock;
445
446 sock = ftpfs_open_socket (me, super);
447 if (sock != -1)
448 {
449 char *cwdir = ftp_super->current_dir;
450
451 close (ftp_super->sock);
452 ftp_super->sock = sock;
453 ftp_super->current_dir = NULL;
454
455 if (ftpfs_login_server (me, super, super->path_element->password))
456 {
457 if (cwdir == NULL)
458 return TRUE;
459
460 sock = ftpfs_chdir_internal (me, super, cwdir);
461 g_free (cwdir);
462 return (sock == COMPLETE);
463 }
464
465 ftp_super->current_dir = cwdir;
466 }
467
468 return FALSE;
469 }
470
471
472
473 static int G_GNUC_PRINTF (4, 5)
474 ftpfs_command (struct vfs_class *me, struct vfs_s_super *super, int wait_reply, const char *fmt,
475 ...)
476 {
477 ftp_super_t *ftp_super = FTP_SUPER (super);
478 va_list ap;
479 GString *cmdstr;
480 int status;
481 static gboolean retry = FALSE;
482 static int level = 0;
483
484 cmdstr = g_string_sized_new (32);
485 va_start (ap, fmt);
486 g_string_vprintf (cmdstr, fmt, ap);
487 va_end (ap);
488 g_string_append (cmdstr, "\r\n");
489
490 if (me->logfile != NULL)
491 {
492 if (strncmp (cmdstr->str, "PASS ", 5) == 0)
493 fputs ("PASS <Password not logged>\r\n", me->logfile);
494 else
495 {
496 size_t ret;
497
498 ret = fwrite (cmdstr->str, cmdstr->len, 1, me->logfile);
499 (void) ret;
500 }
501
502 fflush (me->logfile);
503 }
504
505 got_sigpipe = 0;
506 tty_enable_interrupt_key ();
507 status = write (ftp_super->sock, cmdstr->str, cmdstr->len);
508
509 if (status < 0)
510 {
511 code = 421;
512
513 if (errno == EPIPE)
514 {
515 if (level == 0)
516 {
517 level = 1;
518 status = ftpfs_reconnect (me, super) ? 1 : 0;
519 level = 0;
520 if (status != 0 && (write (ftp_super->sock, cmdstr->str, cmdstr->len) > 0))
521 goto ok;
522 }
523 got_sigpipe = 1;
524 }
525 g_string_free (cmdstr, TRUE);
526 tty_disable_interrupt_key ();
527 return TRANSIENT;
528 }
529
530 retry = FALSE;
531
532 ok:
533 tty_disable_interrupt_key ();
534
535 if (wait_reply != NONE)
536 {
537 status = ftpfs_get_reply (me, ftp_super->sock,
538 (wait_reply & WANT_STRING) != 0 ? reply_str : NULL,
539 sizeof (reply_str) - 1);
540
541
542
543 if (!retry && level == 0 && code == 421)
544 {
545 retry = TRUE;
546 level = 1;
547 status = ftpfs_reconnect (me, super) ? 1 : 0;
548 level = 0;
549 if (status != 0 && (write (ftp_super->sock, cmdstr->str, cmdstr->len) > 0))
550 goto ok;
551 }
552 retry = FALSE;
553 g_string_free (cmdstr, TRUE);
554 return status;
555 }
556
557 g_string_free (cmdstr, TRUE);
558 return COMPLETE;
559 }
560
561
562
563 static struct vfs_s_super *
564 ftpfs_new_archive (struct vfs_class *me)
565 {
566 ftp_super_t *arch;
567
568 arch = g_new0 (ftp_super_t, 1);
569 arch->base.me = me;
570 arch->base.name = g_strdup (PATH_SEP_STR);
571 arch->sock = -1;
572 arch->use_passive_connection = ftpfs_use_passive_connections;
573 arch->strict = ftpfs_use_unix_list_options ? RFC_AUTODETECT : RFC_STRICT;
574 arch->isbinary = TYPE_UNKNOWN;
575
576 return VFS_SUPER (arch);
577 }
578
579
580
581 static void
582 ftpfs_free_archive (struct vfs_class *me, struct vfs_s_super *super)
583 {
584 ftp_super_t *ftp_super = FTP_SUPER (super);
585
586 if (ftp_super->sock != -1)
587 {
588 vfs_print_message (_ ("ftpfs: Disconnecting from %s"), super->path_element->host);
589 ftpfs_command (me, super, NONE, "%s", "QUIT");
590 close (ftp_super->sock);
591 }
592 g_free (ftp_super->current_dir);
593 }
594
595
596
597 static int
598 ftpfs_changetype (struct vfs_class *me, struct vfs_s_super *super, int binary)
599 {
600 if (binary != FTP_SUPER (super)->isbinary)
601 {
602 if (ftpfs_command (me, super, WAIT_REPLY, "TYPE %c", binary ? 'I' : 'A') != COMPLETE)
603 ERRNOR (EIO, -1);
604 FTP_SUPER (super)->isbinary = binary;
605 }
606 return binary;
607 }
608
609
610
611
612 static int
613 ftpfs_login_server (struct vfs_class *me, struct vfs_s_super *super, const char *netrcpass)
614 {
615 ftp_super_t *ftp_super = FTP_SUPER (super);
616 char *pass;
617 char *op;
618 char *name;
619 gboolean anon = FALSE;
620 char reply_string[BUF_MEDIUM];
621
622 ftp_super->isbinary = TYPE_UNKNOWN;
623
624 if (super->path_element->password != NULL)
625 op = g_strdup (super->path_element->password);
626 else if (netrcpass != NULL)
627 op = g_strdup (netrcpass);
628 else if (strcmp (super->path_element->user, "anonymous") == 0
629 || strcmp (super->path_element->user, "ftp") == 0)
630 {
631 if (ftpfs_anonymous_passwd == NULL)
632 ftpfs_init_passwd ();
633 op = g_strdup (ftpfs_anonymous_passwd);
634 anon = TRUE;
635 }
636 else
637 {
638 char *p;
639
640 p = g_strdup_printf (_ ("FTP: Password required for %s"), super->path_element->user);
641 op = vfs_get_password (p);
642 g_free (p);
643 if (op == NULL)
644 ERRNOR (EPERM, 0);
645 super->path_element->password = g_strdup (op);
646 }
647
648 if (!anon || me->logfile != NULL)
649 pass = op;
650 else
651 {
652 pass = g_strconcat ("-", op, (char *) NULL);
653 wipe_password (op);
654 }
655
656
657 if (ftp_super->proxy != NULL)
658 name = g_strconcat (super->path_element->user, "@",
659 super->path_element->host[0] == '!' ? super->path_element->host + 1
660 : super->path_element->host,
661 (char *) NULL);
662 else
663 name = g_strdup (super->path_element->user);
664
665 if (ftpfs_get_reply (me, ftp_super->sock, reply_string, sizeof (reply_string) - 1) == COMPLETE)
666 {
667 char *reply_up;
668
669 reply_up = g_ascii_strup (reply_string, -1);
670 ftp_super->remote_is_amiga = strstr (reply_up, "AMIGA") != NULL;
671 if (strstr (reply_up, " SPFTP/1.0.0000 SERVER ")
672 != NULL)
673 ftp_super->strict = RFC_STRICT;
674 g_free (reply_up);
675
676 if (me->logfile != NULL)
677 {
678 fprintf (me->logfile, "MC -- remote_is_amiga = %s\n",
679 ftp_super->remote_is_amiga ? "yes" : "no");
680 fflush (me->logfile);
681 }
682
683 vfs_print_message ("%s", _ ("ftpfs: sending login name"));
684
685 switch (ftpfs_command (me, super, WAIT_REPLY, "USER %s", name))
686 {
687 case CONTINUE:
688 vfs_print_message ("%s", _ ("ftpfs: sending user password"));
689 code = ftpfs_command (me, super, WAIT_REPLY, "PASS %s", pass);
690 if (code == CONTINUE)
691 {
692 char *p;
693
694 p = g_strdup_printf (_ ("FTP: Account required for user %s"),
695 super->path_element->user);
696 op = input_dialog (p, _ ("Account:"), MC_HISTORY_FTPFS_ACCOUNT, "",
697 INPUT_COMPLETE_USERNAMES);
698 g_free (p);
699 if (op == NULL)
700 ERRNOR (EPERM, 0);
701 vfs_print_message ("%s", _ ("ftpfs: sending user account"));
702 code = ftpfs_command (me, super, WAIT_REPLY, "ACCT %s", op);
703 g_free (op);
704 }
705 if (code != COMPLETE)
706 break;
707
708 MC_FALLTHROUGH;
709
710 case COMPLETE:
711 vfs_print_message ("%s", _ ("ftpfs: logged in"));
712 wipe_password (pass);
713 g_free (name);
714 return TRUE;
715
716 default:
717 ftp_super->failed_on_login = TRUE;
718 wipe_password (super->path_element->password);
719 super->path_element->password = NULL;
720 goto login_fail;
721 }
722 }
723
724 message (D_ERROR, MSG_ERROR, _ ("ftpfs: Login incorrect for user %s "),
725 super->path_element->user);
726
727 login_fail:
728 wipe_password (pass);
729 g_free (name);
730 ERRNOR (EPERM, FALSE);
731 }
732
733
734
735 static void
736 ftpfs_load_no_proxy_list (void)
737 {
738
739 char *mc_file;
740
741 mc_file = g_build_filename (mc_global.sysconfig_dir, "mc.no_proxy", (char *) NULL);
742 if (exist_file (mc_file))
743 {
744 FILE *npf;
745
746 npf = fopen (mc_file, "r");
747 if (npf != NULL)
748 {
749 char s[BUF_LARGE];
750
751 while (fgets (s, sizeof (s), npf) != NULL)
752 {
753 char *p;
754
755 p = strchr (s, '\n');
756 if (p == NULL)
757 {
758 int c;
759
760 while ((c = fgetc (npf)) != EOF && c != '\n')
761 ;
762 }
763 else if (p != s)
764 {
765 *p = '\0';
766 no_proxy = g_slist_prepend (no_proxy, g_strdup (s));
767 }
768 }
769
770 fclose (npf);
771 }
772 }
773
774 g_free (mc_file);
775 }
776
777
778
779
780 static gboolean
781 ftpfs_check_proxy (const char *host)
782 {
783
784 if (ftpfs_proxy_host == NULL || *ftpfs_proxy_host == '\0' || host == NULL || *host == '\0')
785 return FALSE;
786
787 if (*host == '!')
788 return TRUE;
789
790 if (!ftpfs_always_use_proxy)
791 return FALSE;
792
793 if (strchr (host, '.') == NULL)
794 return FALSE;
795
796 if (no_proxy == NULL)
797 {
798 GSList *npe;
799
800 ftpfs_load_no_proxy_list ();
801
802 for (npe = no_proxy; npe != NULL; npe = g_slist_next (npe))
803 {
804 const char *domain = (const char *) npe->data;
805
806 if (domain[0] == '.')
807 {
808 size_t ld, lh;
809
810 ld = strlen (domain);
811 lh = strlen (host);
812
813 while (ld != 0 && lh != 0 && host[lh - 1] == domain[ld - 1])
814 {
815 ld--;
816 lh--;
817 }
818
819 if (ld == 0)
820 return FALSE;
821 }
822 else if (g_ascii_strcasecmp (host, domain) == 0)
823 return FALSE;
824 }
825 }
826
827 return TRUE;
828 }
829
830
831
832 static void
833 ftpfs_get_proxy_host_and_port (const char *proxy, char **host, int *port)
834 {
835 vfs_path_element_t *path_element;
836
837 path_element = vfs_url_split (proxy, FTP_COMMAND_PORT, URL_USE_ANONYMOUS);
838 *host = path_element->host;
839 path_element->host = NULL;
840 *port = path_element->port;
841 vfs_path_element_free (path_element);
842 }
843
844
845
846 static int
847 ftpfs_open_socket (struct vfs_class *me, struct vfs_s_super *super)
848 {
849 struct addrinfo hints, *res, *curr_res;
850 int my_socket = 0;
851 char *host = NULL;
852 char port[8];
853 int tmp_port = 0;
854 int e;
855
856 (void) me;
857
858 if (super->path_element->host == NULL || *super->path_element->host == '\0')
859 {
860 vfs_print_message ("%s", _ ("ftpfs: Invalid host name."));
861 me->verrno = EINVAL;
862 return (-1);
863 }
864
865
866
867 if (FTP_SUPER (super)->proxy != NULL)
868 ftpfs_get_proxy_host_and_port (ftpfs_proxy_host, &host, &tmp_port);
869 else
870 {
871 host = g_strdup (super->path_element->host);
872 tmp_port = super->path_element->port;
873 }
874
875 g_snprintf (port, sizeof (port), "%hu", (unsigned short) tmp_port);
876
877 tty_enable_interrupt_key ();
878
879 memset (&hints, 0, sizeof (hints));
880 hints.ai_family = AF_UNSPEC;
881 hints.ai_socktype = SOCK_STREAM;
882
883 #ifdef AI_ADDRCONFIG
884
885
886
887 hints.ai_flags = AI_ADDRCONFIG;
888 #endif
889
890 e = getaddrinfo (host, port, &hints, &res);
891
892 #ifdef AI_ADDRCONFIG
893 if (e == EAI_BADFLAGS)
894 {
895
896 hints.ai_flags = 0;
897 e = getaddrinfo (host, port, &hints, &res);
898 }
899 #endif
900
901 *port = '\0';
902
903 if (e != 0)
904 {
905 tty_disable_interrupt_key ();
906 vfs_print_message (_ ("ftpfs: %s"), gai_strerror (e));
907 g_free (host);
908 me->verrno = EINVAL;
909 return (-1);
910 }
911
912 for (curr_res = res; curr_res != NULL; curr_res = curr_res->ai_next)
913 {
914 my_socket = socket (curr_res->ai_family, curr_res->ai_socktype, curr_res->ai_protocol);
915
916 if (my_socket < 0)
917 {
918 if (curr_res->ai_next != NULL)
919 continue;
920
921 tty_disable_interrupt_key ();
922 vfs_print_message (_ ("ftpfs: %s"), unix_error_string (errno));
923 g_free (host);
924 freeaddrinfo (res);
925 me->verrno = errno;
926 return (-1);
927 }
928
929 vfs_print_message (_ ("ftpfs: making connection to %s"), host);
930 MC_PTR_FREE (host);
931
932 if (connect (my_socket, curr_res->ai_addr, curr_res->ai_addrlen) >= 0)
933 break;
934
935 me->verrno = errno;
936 close (my_socket);
937
938 if (me->verrno == EINTR && tty_got_interrupt ())
939 vfs_print_message ("%s", _ ("ftpfs: connection interrupted by user"));
940 else if (res->ai_next == NULL)
941 vfs_print_message (_ ("ftpfs: connection to server failed: %s"),
942 unix_error_string (errno));
943 else
944 continue;
945
946 freeaddrinfo (res);
947 tty_disable_interrupt_key ();
948 return (-1);
949 }
950
951 freeaddrinfo (res);
952 tty_disable_interrupt_key ();
953 return my_socket;
954 }
955
956
957
958 static int
959 ftpfs_open_archive_int (struct vfs_class *me, struct vfs_s_super *super)
960 {
961 ftp_super_t *ftp_super = FTP_SUPER (super);
962 int retry_seconds = 0;
963
964
965 if (ftp_super->proxy != NULL)
966 ftp_super->use_passive_connection = ftpfs_use_passive_connections_over_proxy;
967
968 do
969 {
970 ftp_super->failed_on_login = FALSE;
971
972 ftp_super->sock = ftpfs_open_socket (me, super);
973 if (ftp_super->sock == -1)
974 return (-1);
975
976 if (ftpfs_login_server (me, super, NULL))
977 {
978
979 break;
980 }
981
982 if (!ftp_super->failed_on_login)
983 return (-1);
984
985
986 close (ftp_super->sock);
987
988 if (ftpfs_retry_seconds != 0)
989 {
990 int count_down;
991
992 retry_seconds = ftpfs_retry_seconds;
993 tty_enable_interrupt_key ();
994 for (count_down = retry_seconds; count_down != 0; count_down--)
995 {
996 vfs_print_message (_ ("Waiting to retry... %d (Control-G to cancel)"), count_down);
997 sleep (1);
998 if (tty_got_interrupt ())
999 {
1000
1001 tty_disable_interrupt_key ();
1002 return 0;
1003 }
1004 }
1005 tty_disable_interrupt_key ();
1006 }
1007 }
1008 while (retry_seconds != 0);
1009
1010 ftp_super->current_dir = ftpfs_get_current_directory (me, super);
1011 if (ftp_super->current_dir == NULL)
1012 ftp_super->current_dir = g_strdup (PATH_SEP_STR);
1013
1014 return 0;
1015 }
1016
1017
1018
1019 static int
1020 ftpfs_open_archive (struct vfs_s_super *super, const vfs_path_t *vpath,
1021 const vfs_path_element_t *vpath_element)
1022 {
1023 (void) vpath;
1024
1025 super->path_element = ftpfs_correct_url_parameters (vpath_element);
1026 if (ftpfs_check_proxy (super->path_element->host))
1027 FTP_SUPER (super)->proxy = ftpfs_proxy_host;
1028 super->root =
1029 vfs_s_new_inode (vpath_element->class, super, ftpfs_default_stat (vpath_element->class));
1030
1031 return ftpfs_open_archive_int (vpath_element->class, super);
1032 }
1033
1034
1035
1036 static int
1037 ftpfs_archive_same (const vfs_path_element_t *vpath_element, struct vfs_s_super *super,
1038 const vfs_path_t *vpath, void *cookie)
1039 {
1040 vfs_path_element_t *path_element;
1041 int result;
1042
1043 (void) vpath;
1044 (void) cookie;
1045
1046 path_element = ftpfs_correct_url_parameters (vpath_element);
1047
1048 result = ((strcmp (path_element->host, super->path_element->host) == 0)
1049 && (strcmp (path_element->user, super->path_element->user) == 0)
1050 && (path_element->port == super->path_element->port))
1051 ? 1
1052 : 0;
1053
1054 vfs_path_element_free (path_element);
1055 return result;
1056 }
1057
1058
1059
1060
1061 static char *
1062 ftpfs_get_current_directory (struct vfs_class *me, struct vfs_s_super *super)
1063 {
1064 char buf[MC_MAXPATHLEN + 1];
1065
1066 if (ftpfs_command (me, super, NONE, "%s", "PWD") == COMPLETE
1067 && ftpfs_get_reply (me, FTP_SUPER (super)->sock, buf, sizeof (buf)) == COMPLETE)
1068 {
1069 char *bufp = NULL;
1070 char *bufq;
1071
1072 for (bufq = buf; *bufq != '\0'; bufq++)
1073 if (*bufq == '"')
1074 {
1075 if (bufp == NULL)
1076 bufp = bufq + 1;
1077 else
1078 {
1079 *bufq = '\0';
1080
1081 if (*bufp != '\0')
1082 {
1083 if (!IS_PATH_SEP (bufq[-1]))
1084 {
1085 *bufq++ = PATH_SEP;
1086 *bufq = '\0';
1087 }
1088
1089 if (IS_PATH_SEP (*bufp))
1090 return g_strdup (bufp);
1091
1092
1093
1094
1095 return g_strconcat (PATH_SEP_STR, bufp, (char *) NULL);
1096 }
1097
1098 break;
1099 }
1100 }
1101 }
1102
1103 me->verrno = EIO;
1104 return NULL;
1105 }
1106
1107
1108
1109
1110 static gboolean
1111 ftpfs_setup_passive_pasv (struct vfs_class *me, struct vfs_s_super *super, int my_socket,
1112 struct sockaddr_storage *sa, socklen_t *salen)
1113 {
1114 char *c;
1115 char n[6];
1116 int xa, xb, xc, xd, xe, xf;
1117
1118 if (ftpfs_command (me, super, WAIT_REPLY | WANT_STRING, "%s", "PASV") != COMPLETE)
1119 return FALSE;
1120
1121
1122 for (c = reply_str + 4; *c != '\0' && !isdigit ((unsigned char) *c); c++)
1123 ;
1124
1125 if (*c == '\0' || !isdigit ((unsigned char) *c))
1126 return FALSE;
1127
1128 if (sscanf (c, "%d,%d,%d,%d,%d,%d", &xa, &xb, &xc, &xd, &xe, &xf) != 6)
1129 return FALSE;
1130
1131 n[0] = (unsigned char) xa;
1132 n[1] = (unsigned char) xb;
1133 n[2] = (unsigned char) xc;
1134 n[3] = (unsigned char) xd;
1135 n[4] = (unsigned char) xe;
1136 n[5] = (unsigned char) xf;
1137
1138 memcpy (&(((struct sockaddr_in *) sa)->sin_addr.s_addr), (void *) n, 4);
1139 memcpy (&(((struct sockaddr_in *) sa)->sin_port), (void *) &n[4], 2);
1140
1141 return (connect (my_socket, (struct sockaddr *) sa, *salen) >= 0);
1142 }
1143
1144
1145
1146
1147 static gboolean
1148 ftpfs_setup_passive_epsv (struct vfs_class *me, struct vfs_s_super *super, int my_socket,
1149 struct sockaddr_storage *sa, socklen_t *salen)
1150 {
1151 char *c;
1152 int port;
1153
1154 if (ftpfs_command (me, super, WAIT_REPLY | WANT_STRING, "%s", "EPSV") != COMPLETE)
1155 return FALSE;
1156
1157
1158 c = strchr (reply_str, '|');
1159 if (c == NULL || strlen (c) <= 3)
1160 return FALSE;
1161
1162 c += 3;
1163 port = atoi (c);
1164 if (port < 0 || port > 65535)
1165 return FALSE;
1166
1167 port = htons (port);
1168
1169 switch (sa->ss_family)
1170 {
1171 case AF_INET:
1172 ((struct sockaddr_in *) sa)->sin_port = port;
1173 break;
1174 case AF_INET6:
1175 ((struct sockaddr_in6 *) sa)->sin6_port = port;
1176 break;
1177 default:
1178 break;
1179 }
1180
1181 return (connect (my_socket, (struct sockaddr *) sa, *salen) >= 0);
1182 }
1183
1184
1185
1186
1187 static gboolean
1188 ftpfs_setup_passive (struct vfs_class *me, struct vfs_s_super *super, int my_socket,
1189 struct sockaddr_storage *sa, socklen_t *salen)
1190 {
1191
1192 if (sa->ss_family == AF_INET)
1193 {
1194 if (!ftpfs_setup_passive_pasv (me, super, my_socket, sa, salen))
1195
1196 if (!ftpfs_setup_passive_epsv (me, super, my_socket, sa, salen))
1197 return FALSE;
1198 }
1199
1200 else if (!ftpfs_setup_passive_epsv (me, super, my_socket, sa, salen))
1201 return FALSE;
1202
1203 return TRUE;
1204 }
1205
1206
1207
1208
1209 static int
1210 ftpfs_setup_active (struct vfs_class *me, struct vfs_s_super *super,
1211 struct sockaddr_storage data_addr, socklen_t data_addrlen)
1212 {
1213 unsigned short int port;
1214 char *addr;
1215 unsigned int af;
1216 int res;
1217
1218 switch (data_addr.ss_family)
1219 {
1220 case AF_INET:
1221 af = FTP_INET;
1222 port = ((struct sockaddr_in *) &data_addr)->sin_port;
1223 break;
1224 case AF_INET6:
1225 af = FTP_INET6;
1226 port = ((struct sockaddr_in6 *) &data_addr)->sin6_port;
1227 break;
1228 default:
1229
1230 return 0;
1231 }
1232
1233 addr = g_try_malloc (NI_MAXHOST);
1234 if (addr == NULL)
1235 ERRNOR (ENOMEM, -1);
1236
1237 res = getnameinfo ((struct sockaddr *) &data_addr, data_addrlen, addr, NI_MAXHOST, NULL, 0,
1238 NI_NUMERICHOST);
1239 if (res != 0)
1240 {
1241 const char *err_str;
1242
1243 g_free (addr);
1244
1245 if (res == EAI_SYSTEM)
1246 {
1247 me->verrno = errno;
1248 err_str = unix_error_string (me->verrno);
1249 }
1250 else
1251 {
1252 me->verrno = EIO;
1253 err_str = gai_strerror (res);
1254 }
1255
1256 vfs_print_message (_ ("ftpfs: could not make address-to-name translation: %s"), err_str);
1257
1258 return (-1);
1259 }
1260
1261
1262 if (af == FTP_INET)
1263 {
1264 unsigned char *a = (unsigned char *) &((struct sockaddr_in *) &data_addr)->sin_addr;
1265 unsigned char *p = (unsigned char *) &port;
1266
1267 if (ftpfs_command (me, super, WAIT_REPLY, "PORT %u,%u,%u,%u,%u,%u", a[0], a[1], a[2], a[3],
1268 p[0], p[1])
1269 == COMPLETE)
1270 {
1271 g_free (addr);
1272 return 1;
1273 }
1274 }
1275
1276
1277
1278
1279
1280
1281
1282 port = ntohs (port);
1283
1284
1285 res = (ftpfs_command (me, super, WAIT_REPLY, "EPRT |%u|%s|%hu|", af, addr, port) == COMPLETE)
1286 ? 1
1287 : 0;
1288 g_free (addr);
1289 return res;
1290 }
1291
1292
1293
1294
1295 static int
1296 ftpfs_init_data_socket (struct vfs_class *me, struct vfs_s_super *super,
1297 struct sockaddr_storage *data_addr, socklen_t *data_addrlen)
1298 {
1299 const unsigned int attempts = 10;
1300 unsigned int i;
1301 ftp_super_t *ftp_super = FTP_SUPER (super);
1302 int result;
1303
1304 for (i = 0; i < attempts; i++)
1305 {
1306 memset (data_addr, 0, sizeof (*data_addr));
1307 *data_addrlen = sizeof (*data_addr);
1308
1309 if (ftp_super->use_passive_connection)
1310 {
1311 result = getpeername (ftp_super->sock, (struct sockaddr *) data_addr, data_addrlen);
1312 if (result == 0)
1313 break;
1314
1315 me->verrno = errno;
1316
1317 if (me->verrno == ENOTCONN)
1318 {
1319 vfs_print_message (_ ("ftpfs: try reconnect to server, attempt %u"), i);
1320 if (ftpfs_reconnect (me, super))
1321 continue;
1322 }
1323 else
1324 {
1325
1326 vfs_print_message (_ ("ftpfs: could not get socket name: %s"),
1327 unix_error_string (me->verrno));
1328 }
1329 }
1330 else
1331 {
1332 result = getsockname (ftp_super->sock, (struct sockaddr *) data_addr, data_addrlen);
1333 if (result == 0)
1334 break;
1335
1336 me->verrno = errno;
1337
1338 vfs_print_message (_ ("ftpfs: try reconnect to server, attempt %u"), i);
1339 if (ftpfs_reconnect (me, super))
1340 continue;
1341
1342
1343 vfs_print_message ("%s", _ ("ftpfs: could not reconnect to server"));
1344 }
1345
1346 i = attempts;
1347 }
1348
1349 if (i >= attempts)
1350 return (-1);
1351
1352 switch (data_addr->ss_family)
1353 {
1354 case AF_INET:
1355 ((struct sockaddr_in *) data_addr)->sin_port = 0;
1356 break;
1357 case AF_INET6:
1358 ((struct sockaddr_in6 *) data_addr)->sin6_port = 0;
1359 break;
1360 default:
1361 vfs_print_message ("%s", _ ("ftpfs: invalid address family"));
1362 ERRNOR (EINVAL, -1);
1363 }
1364
1365 result = socket (data_addr->ss_family, SOCK_STREAM, IPPROTO_TCP);
1366 if (result < 0)
1367 {
1368 me->verrno = errno;
1369 vfs_print_message (_ ("ftpfs: could not create socket: %s"),
1370 unix_error_string (me->verrno));
1371 result = -1;
1372 }
1373
1374 return result;
1375 }
1376
1377
1378
1379
1380 static int
1381 ftpfs_initconn (struct vfs_class *me, struct vfs_s_super *super)
1382 {
1383 ftp_super_t *ftp_super = FTP_SUPER (super);
1384 struct sockaddr_storage data_addr;
1385 socklen_t data_addrlen;
1386
1387
1388
1389
1390
1391
1392
1393
1394 if (ftp_super->use_passive_connection)
1395 {
1396 int data_sock;
1397
1398 data_sock = ftpfs_init_data_socket (me, super, &data_addr, &data_addrlen);
1399 if (data_sock < 0)
1400 return (-1);
1401
1402 if (ftpfs_setup_passive (me, super, data_sock, &data_addr, &data_addrlen))
1403 return data_sock;
1404
1405 vfs_print_message ("%s", _ ("ftpfs: could not setup passive mode"));
1406 ftp_super->use_passive_connection = FALSE;
1407
1408 close (data_sock);
1409 }
1410
1411
1412 if (!ftp_super->use_passive_connection)
1413 {
1414 int data_sock;
1415
1416 data_sock = ftpfs_init_data_socket (me, super, &data_addr, &data_addrlen);
1417 if (data_sock < 0)
1418 return (-1);
1419
1420 if ((bind (data_sock, (struct sockaddr *) &data_addr, data_addrlen) != 0)
1421 || (getsockname (data_sock, (struct sockaddr *) &data_addr, &data_addrlen) != 0)
1422 || (listen (data_sock, 1) != 0))
1423 {
1424 close (data_sock);
1425 ERRNOR (errno, -1);
1426 }
1427
1428 if (ftpfs_setup_active (me, super, data_addr, data_addrlen) != 0)
1429 return data_sock;
1430
1431 close (data_sock);
1432 }
1433
1434
1435 ftp_super->use_passive_connection = ftp_super->proxy != NULL
1436 ? ftpfs_use_passive_connections_over_proxy
1437 : ftpfs_use_passive_connections;
1438
1439 me->verrno = EIO;
1440 return (-1);
1441 }
1442
1443
1444
1445 static int
1446 ftpfs_open_data_connection (struct vfs_class *me, struct vfs_s_super *super, const char *cmd,
1447 const char *remote, int isbinary, int reget)
1448 {
1449 ftp_super_t *ftp_super = FTP_SUPER (super);
1450 int s, j, data;
1451
1452
1453 if (ftp_super->ctl_connection_busy)
1454 return (-1);
1455
1456 s = ftpfs_initconn (me, super);
1457 if (s == -1)
1458 return (-1);
1459
1460 if (ftpfs_changetype (me, super, isbinary) == -1)
1461 {
1462 close (s);
1463 return (-1);
1464 }
1465
1466 if (reget > 0)
1467 {
1468 j = ftpfs_command (me, super, WAIT_REPLY, "REST %d", reget);
1469 if (j != CONTINUE)
1470 {
1471 close (s);
1472 ERRNOR (EIO, -1);
1473 }
1474 }
1475
1476 if (remote == NULL)
1477 j = ftpfs_command (me, super, WAIT_REPLY, "%s", cmd);
1478 else
1479 {
1480 char *remote_path;
1481
1482 remote_path = ftpfs_translate_path (me, super, remote);
1483 j = ftpfs_command (me, super, WAIT_REPLY, "%s /%s", cmd,
1484
1485 IS_PATH_SEP (*remote_path) ? remote_path + 1 : remote_path);
1486 g_free (remote_path);
1487 }
1488
1489 if (j != PRELIM)
1490 {
1491 close (s);
1492 ERRNOR (EPERM, -1);
1493 }
1494
1495 if (ftp_super->use_passive_connection)
1496 data = s;
1497 else
1498 {
1499 struct sockaddr_storage from;
1500 socklen_t fromlen = sizeof (from);
1501
1502 tty_enable_interrupt_key ();
1503 data = accept (s, (struct sockaddr *) &from, &fromlen);
1504 if (data < 0)
1505 me->verrno = errno;
1506 tty_disable_interrupt_key ();
1507 close (s);
1508 if (data < 0)
1509 return (-1);
1510 }
1511
1512 ftp_super->ctl_connection_busy = TRUE;
1513 return data;
1514 }
1515
1516
1517
1518 static void
1519 ftpfs_linear_abort (struct vfs_class *me, vfs_file_handler_t *fh)
1520 {
1521 struct vfs_s_super *super = VFS_FILE_HANDLER_SUPER (fh);
1522 ftp_super_t *ftp_super = FTP_SUPER (super);
1523 static unsigned char const ipbuf[3] = { IAC, IP, IAC };
1524 fd_set mask;
1525 int dsock = FH_SOCK;
1526
1527 FH_SOCK = -1;
1528 ftp_super->ctl_connection_busy = FALSE;
1529
1530 vfs_print_message ("%s", _ ("ftpfs: aborting transfer."));
1531
1532 if (send (ftp_super->sock, ipbuf, sizeof (ipbuf), MSG_OOB) != sizeof (ipbuf))
1533 {
1534 vfs_print_message (_ ("ftpfs: abort error: %s"), unix_error_string (errno));
1535 if (dsock != -1)
1536 close (dsock);
1537 return;
1538 }
1539
1540 if (ftpfs_command (me, super, NONE, "%cABOR", DM) != COMPLETE)
1541 {
1542 vfs_print_message ("%s", _ ("ftpfs: abort failed"));
1543 if (dsock != -1)
1544 close (dsock);
1545 return;
1546 }
1547
1548 if (dsock != -1)
1549 {
1550 FD_ZERO (&mask);
1551 FD_SET (dsock, &mask);
1552
1553 if (select (dsock + 1, &mask, NULL, NULL, NULL) > 0)
1554 {
1555 gint64 start_tim;
1556 char buf[BUF_8K];
1557
1558 start_tim = g_get_monotonic_time ();
1559
1560
1561 while (read (dsock, buf, sizeof (buf)) > 0)
1562 {
1563 gint64 tim;
1564
1565 tim = g_get_monotonic_time ();
1566
1567 if (tim > start_tim + ABORT_TIMEOUT)
1568 {
1569
1570 close (dsock);
1571 ftpfs_reconnect (me, super);
1572 return;
1573 }
1574 }
1575 }
1576 close (dsock);
1577 }
1578
1579 if ((ftpfs_get_reply (me, ftp_super->sock, NULL, 0) == TRANSIENT) && (code == 426))
1580 ftpfs_get_reply (me, ftp_super->sock, NULL, 0);
1581 }
1582
1583
1584
1585 #if 0
1586 static void
1587 resolve_symlink_without_ls_options (struct vfs_class *me, struct vfs_s_super *super,
1588 struct vfs_s_inode *dir)
1589 {
1590 struct linklist *flist;
1591 struct direntry *fe, *fel;
1592 char tmp[MC_MAXPATHLEN];
1593
1594 dir->symlink_status = FTPFS_RESOLVING_SYMLINKS;
1595 for (flist = dir->file_list->next; flist != dir->file_list; flist = flist->next)
1596 {
1597
1598 fel = flist->data;
1599 if (S_ISLNK (fel->s.st_mode) && fel->linkname != NULL)
1600 {
1601 int depth;
1602
1603 if (IS_PATH_SEP (fel->linkname[0]))
1604 {
1605 if (strlen (fel->linkname) >= MC_MAXPATHLEN)
1606 continue;
1607 strcpy (tmp, fel->linkname);
1608 }
1609 else
1610 {
1611 if ((strlen (dir->remote_path) + strlen (fel->linkname)) >= MC_MAXPATHLEN)
1612 continue;
1613 strcpy (tmp, dir->remote_path);
1614 if (tmp[1] != '\0')
1615 strcat (tmp, PATH_SEP_STR);
1616 strcat (tmp + 1, fel->linkname);
1617 }
1618
1619 for (depth = 0; depth < 100; depth++)
1620 {
1621 canonicalize_pathname (tmp);
1622 fe = _get_file_entry_t (bucket, tmp, 0, 0);
1623 if (fe != NULL)
1624 {
1625 if (S_ISLNK (fe->s.st_mode) && fe->l_stat == 0)
1626 {
1627
1628 if (IS_PATH_SEP (fe->linkname[0]))
1629 {
1630 if (strlen (fe->linkname) >= MC_MAXPATHLEN)
1631 break;
1632 strcpy (tmp, fe->linkname);
1633 }
1634 else
1635 {
1636
1637
1638
1639 *(strrchr (tmp, PATH_SEP) + 1) = '\0';
1640 if ((strlen (tmp) + strlen (fe->linkname)) >= MC_MAXPATHLEN)
1641 break;
1642 strcat (tmp, fe->linkname);
1643 }
1644 continue;
1645 }
1646 else
1647 {
1648 fel->l_stat = g_new (struct stat, 1);
1649 if (S_ISLNK (fe->s.st_mode))
1650 *fel->l_stat = *fe->l_stat;
1651 else
1652 *fel->l_stat = fe->s;
1653 (*fel->l_stat).st_ino = bucket->__inode_counter++;
1654 }
1655 }
1656 break;
1657 }
1658 }
1659 }
1660
1661 dir->symlink_status = FTPFS_RESOLVED_SYMLINKS;
1662 }
1663
1664
1665
1666 static void
1667 resolve_symlink_with_ls_options (struct vfs_class *me, struct vfs_s_super *super,
1668 struct vfs_s_inode *dir)
1669 {
1670 char buffer[BUF_2K] = "";
1671 char *filename;
1672 int sock;
1673 FILE *fp;
1674 struct stat s;
1675 struct linklist *flist;
1676 struct direntry *fe;
1677 int switch_method = 0;
1678
1679 dir->symlink_status = FTPFS_RESOLVED_SYMLINKS;
1680 if (strchr (dir->remote_path, ' ') == NULL)
1681 sock = ftpfs_open_data_connection (bucket, "LIST -lLa", dir->remote_path, TYPE_ASCII, 0);
1682 else
1683 {
1684 if (ftpfs_chdir_internal (bucket, dir->remote_path) != COMPLETE)
1685 {
1686 vfs_print_message ("%s", _("ftpfs: CWD failed."));
1687 return;
1688 }
1689
1690 sock = ftpfs_open_data_connection (bucket, "LIST -lLa", ".", TYPE_ASCII, 0);
1691 }
1692
1693 if (sock == -1)
1694 {
1695 vfs_print_message ("%s", _("ftpfs: couldn't resolve symlink"));
1696 return;
1697 }
1698
1699 fp = fdopen (sock, "r");
1700 if (fp == NULL)
1701 {
1702 close (sock);
1703 vfs_print_message ("%s", _("ftpfs: couldn't resolve symlink"));
1704 return;
1705 }
1706 tty_enable_interrupt_key ();
1707 flist = dir->file_list->next;
1708
1709 while (TRUE)
1710 {
1711 do
1712 {
1713 if (flist == dir->file_list)
1714 goto done;
1715
1716 fe = flist->data;
1717 flist = flist->next;
1718 }
1719 while (!S_ISLNK (fe->s.st_mode));
1720
1721 while (TRUE)
1722 {
1723 if (fgets (buffer, sizeof (buffer), fp) == NULL)
1724 goto done;
1725
1726 if (me->logfile != NULL)
1727 {
1728 fputs (buffer, me->logfile);
1729 fflush (me->logfile);
1730 }
1731
1732 vfs_die ("This code should be commented out\n");
1733
1734 if (vfs_parse_ls_lga (buffer, &s, &filename, NULL))
1735 {
1736 int r;
1737
1738 r = strcmp (fe->name, filename);
1739 g_free (filename);
1740 if (r == 0)
1741 {
1742 if (S_ISLNK (s.st_mode))
1743 {
1744
1745 switch_method = 1;
1746 goto done;
1747 }
1748
1749 fe->l_stat = g_try_new (struct stat, 1);
1750 if (fe->l_stat == NULL)
1751 goto done;
1752
1753 *fe->l_stat = s;
1754 (*fe->l_stat).st_ino = bucket->__inode_counter++;
1755 break;
1756 }
1757
1758 if (r < 0)
1759 break;
1760 }
1761 }
1762 }
1763
1764 done:
1765 while (fgets (buffer, sizeof (buffer), fp) != NULL)
1766 ;
1767 tty_disable_interrupt_key ();
1768 fclose (fp);
1769 ftpfs_get_reply (me, FTP_SUPER (super)->sock, NULL, 0);
1770 }
1771
1772
1773
1774 static void
1775 resolve_symlink (struct vfs_class *me, struct vfs_s_super *super, struct vfs_s_inode *dir)
1776 {
1777 vfs_print_message ("%s", _("Resolving symlink..."));
1778
1779 if (FTP_SUPER (super)->strict_rfc959_list_cmd)
1780 resolve_symlink_without_ls_options (me, super, dir);
1781 else
1782 resolve_symlink_with_ls_options (me, super, dir);
1783 }
1784 #endif
1785
1786
1787
1788 static int
1789 ftpfs_dir_load (struct vfs_class *me, struct vfs_s_inode *dir, const char *remote_path)
1790 {
1791 struct vfs_s_super *super = dir->super;
1792 ftp_super_t *ftp_super = FTP_SUPER (super);
1793 int sock;
1794 char lc_buffer[BUF_8K];
1795 int res;
1796 gboolean cd_first;
1797 GSList *dirlist = NULL;
1798 GSList *entlist;
1799 GSList *iter;
1800 int err_count = 0;
1801
1802 cd_first = ftpfs_first_cd_then_ls || (ftp_super->strict == RFC_STRICT)
1803 || (strchr (remote_path, ' ') != NULL);
1804
1805 again:
1806 vfs_print_message (_ ("ftpfs: Reading FTP directory %s... %s%s"), remote_path,
1807 ftp_super->strict == RFC_STRICT ? _ ("(strict rfc959)") : "",
1808 cd_first ? _ ("(chdir first)") : "");
1809
1810 if (cd_first && ftpfs_chdir_internal (me, super, remote_path) != COMPLETE)
1811 {
1812 me->verrno = ENOENT;
1813 vfs_print_message ("%s", _ ("ftpfs: CWD failed."));
1814 return (-1);
1815 }
1816
1817 dir->timestamp = g_get_monotonic_time () + ftpfs_directory_timeout * G_USEC_PER_SEC;
1818
1819 if (ftp_super->strict == RFC_STRICT)
1820 sock = ftpfs_open_data_connection (me, super, "LIST", 0, TYPE_ASCII, 0);
1821 else if (cd_first)
1822
1823
1824 sock = ftpfs_open_data_connection (me, super, "LIST -la", 0, TYPE_ASCII, 0);
1825 else
1826 {
1827 char *path;
1828
1829
1830 path = g_strconcat (remote_path, PATH_SEP_STR ".", (char *) NULL);
1831 sock = ftpfs_open_data_connection (me, super, "LIST -la", path, TYPE_ASCII, 0);
1832 g_free (path);
1833 }
1834
1835 if (sock == -1)
1836 {
1837 fallback:
1838 if (ftp_super->strict == RFC_AUTODETECT)
1839 {
1840
1841
1842 ftp_super->strict = RFC_STRICT;
1843
1844
1845 cd_first = TRUE;
1846 goto again;
1847 }
1848
1849 vfs_print_message ("%s", _ ("ftpfs: failed; nowhere to fallback to"));
1850 ERRNOR (EACCES, -1);
1851 }
1852
1853
1854 while ((res = vfs_s_get_line_interruptible (me, lc_buffer, sizeof (lc_buffer), sock)) != 0)
1855 {
1856 if (res == EINTR)
1857 {
1858 me->verrno = ECONNRESET;
1859 close (sock);
1860 ftp_super->ctl_connection_busy = FALSE;
1861 ftpfs_get_reply (me, ftp_super->sock, NULL, 0);
1862 g_slist_free_full (dirlist, g_free);
1863 vfs_print_message (_ ("%s: failure"), me->name);
1864 return (-1);
1865 }
1866
1867 if (me->logfile != NULL)
1868 {
1869 fputs (lc_buffer, me->logfile);
1870 fputs ("\n", me->logfile);
1871 fflush (me->logfile);
1872 }
1873
1874 dirlist = g_slist_prepend (dirlist, g_strdup (lc_buffer));
1875 }
1876
1877 close (sock);
1878 ftp_super->ctl_connection_busy = FALSE;
1879 me->verrno = E_REMOTE;
1880 if ((ftpfs_get_reply (me, ftp_super->sock, NULL, 0) != COMPLETE))
1881 {
1882 g_slist_free_full (dirlist, g_free);
1883 goto fallback;
1884 }
1885
1886 if (dirlist == NULL && !cd_first)
1887 {
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898 cd_first = TRUE;
1899 goto again;
1900 }
1901
1902
1903 dirlist = g_slist_reverse (dirlist);
1904 entlist = ftpfs_parse_long_list (me, dir, dirlist, &err_count);
1905 g_slist_free_full (dirlist, g_free);
1906
1907 for (iter = entlist; iter != NULL; iter = g_slist_next (iter))
1908 vfs_s_insert_entry (me, dir, VFS_ENTRY (iter->data));
1909
1910 g_slist_free (entlist);
1911
1912 if (ftp_super->strict == RFC_AUTODETECT)
1913 ftp_super->strict = RFC_DARING;
1914
1915 vfs_print_message (_ ("%s: done."), me->name);
1916 return 0;
1917 }
1918
1919
1920
1921 static int
1922 ftpfs_file_store (struct vfs_class *me, vfs_file_handler_t *fh, char *name, char *localname)
1923 {
1924 struct vfs_s_super *super = VFS_FILE_HANDLER_SUPER (fh);
1925 ftp_super_t *ftp_super = FTP_SUPER (super);
1926 ftp_file_handler_t *ftp = FTP_FILE_HANDLER (fh);
1927
1928 int h, sock;
1929 off_t n_stored = 0;
1930 #ifdef HAVE_STRUCT_LINGER_L_LINGER
1931 struct linger li;
1932 #else
1933 int flag_one = 1;
1934 #endif
1935 char lc_buffer[BUF_8K];
1936 struct stat s;
1937 char *w_buf;
1938
1939 h = open (localname, O_RDONLY);
1940 if (h == -1)
1941 ERRNOR (EIO, -1);
1942
1943 if (fstat (h, &s) == -1)
1944 {
1945 me->verrno = errno;
1946 close (h);
1947 return (-1);
1948 }
1949
1950 sock =
1951 ftpfs_open_data_connection (me, super, ftp->append ? "APPE" : "STOR", name, TYPE_BINARY, 0);
1952 if (sock < 0)
1953 {
1954 close (h);
1955 return (-1);
1956 }
1957 #ifdef HAVE_STRUCT_LINGER_L_LINGER
1958 li.l_onoff = 1;
1959 li.l_linger = 120;
1960 setsockopt (sock, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof (li));
1961 #else
1962 setsockopt (sock, SOL_SOCKET, SO_LINGER, &flag_one, sizeof (flag_one));
1963 #endif
1964
1965 tty_enable_interrupt_key ();
1966 while (TRUE)
1967 {
1968 ssize_t n_read, n_written;
1969
1970 while ((n_read = read (h, lc_buffer, sizeof (lc_buffer))) == -1)
1971 {
1972 if (errno != EINTR)
1973 {
1974 me->verrno = errno;
1975 goto error_return;
1976 }
1977 if (tty_got_interrupt ())
1978 {
1979 me->verrno = EINTR;
1980 goto error_return;
1981 }
1982 }
1983 if (n_read == 0)
1984 break;
1985
1986 n_stored += n_read;
1987 w_buf = lc_buffer;
1988
1989 while ((n_written = write (sock, w_buf, n_read)) != n_read)
1990 {
1991 if (n_written == -1)
1992 {
1993 if (errno == EINTR && !tty_got_interrupt ())
1994 continue;
1995
1996 me->verrno = errno;
1997 goto error_return;
1998 }
1999
2000 w_buf += n_written;
2001 n_read -= n_written;
2002 }
2003
2004 vfs_print_message ("%s: %" PRIuMAX "/%" PRIuMAX, _ ("ftpfs: storing file"),
2005 (uintmax_t) n_stored, (uintmax_t) s.st_size);
2006 }
2007 tty_disable_interrupt_key ();
2008
2009 close (sock);
2010 ftp_super->ctl_connection_busy = FALSE;
2011 close (h);
2012
2013 if (ftpfs_get_reply (me, ftp_super->sock, NULL, 0) != COMPLETE)
2014 ERRNOR (EIO, -1);
2015 return 0;
2016
2017 error_return:
2018 tty_disable_interrupt_key ();
2019 close (sock);
2020 ftp_super->ctl_connection_busy = FALSE;
2021 close (h);
2022
2023 ftpfs_get_reply (me, ftp_super->sock, NULL, 0);
2024 return (-1);
2025 }
2026
2027
2028
2029 static int
2030 ftpfs_linear_start (struct vfs_class *me, vfs_file_handler_t *fh, off_t offset)
2031 {
2032 char *name;
2033
2034 name = vfs_s_fullpath (me, fh->ino);
2035 if (name == NULL)
2036 return 0;
2037
2038 FH_SOCK = ftpfs_open_data_connection (me, VFS_FILE_HANDLER_SUPER (fh), "RETR", name,
2039 TYPE_BINARY, offset);
2040 g_free (name);
2041 if (FH_SOCK == -1)
2042 ERRNOR (EACCES, 0);
2043
2044 fh->linear = LS_LINEAR_OPEN;
2045 FTP_FILE_HANDLER (fh)->append = FALSE;
2046 return 1;
2047 }
2048
2049
2050
2051 static ssize_t
2052 ftpfs_linear_read (struct vfs_class *me, vfs_file_handler_t *fh, void *buf, size_t len)
2053 {
2054 ssize_t n;
2055 struct vfs_s_super *super = VFS_FILE_HANDLER_SUPER (fh);
2056
2057 while ((n = read (FH_SOCK, buf, len)) < 0)
2058 {
2059 if ((errno == EINTR) && !tty_got_interrupt ())
2060 continue;
2061 break;
2062 }
2063
2064 if (n < 0)
2065 ftpfs_linear_abort (me, fh);
2066 else if (n == 0)
2067 {
2068 FTP_SUPER (super)->ctl_connection_busy = FALSE;
2069 close (FH_SOCK);
2070 FH_SOCK = -1;
2071 if ((ftpfs_get_reply (me, FTP_SUPER (super)->sock, NULL, 0) != COMPLETE))
2072 ERRNOR (E_REMOTE, -1);
2073 return 0;
2074 }
2075
2076 ERRNOR (errno, n);
2077 }
2078
2079
2080
2081 static void
2082 ftpfs_linear_close (struct vfs_class *me, vfs_file_handler_t *fh)
2083 {
2084 if (FH_SOCK != -1)
2085 ftpfs_linear_abort (me, fh);
2086 }
2087
2088
2089
2090 static int
2091 ftpfs_ctl (void *fh, int ctlop, void *arg)
2092 {
2093 (void) arg;
2094
2095 switch (ctlop)
2096 {
2097 case VFS_CTL_IS_NOTREADY:
2098 {
2099 vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
2100 int v;
2101
2102 if (file->linear == LS_NOT_LINEAR)
2103 vfs_die ("You may not do this");
2104 if (file->linear == LS_LINEAR_CLOSED || file->linear == LS_LINEAR_PREOPEN)
2105 return 0;
2106
2107 v = vfs_s_select_on_two (FH_SOCK, 0);
2108 return (((v < 0) && (errno == EINTR)) || v == 0) ? 1 : 0;
2109 }
2110 default:
2111 return 0;
2112 }
2113 }
2114
2115
2116
2117 static int
2118 ftpfs_send_command (const vfs_path_t *vpath, const char *cmd, int flags)
2119 {
2120 const char *rpath;
2121 char *p;
2122 struct vfs_s_super *super;
2123 int r;
2124 struct vfs_class *me;
2125 gboolean flush_directory_cache = (flags & OPT_FLUSH) != 0;
2126
2127 me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));
2128
2129 rpath = vfs_s_get_path (vpath, &super, 0);
2130 if (rpath == NULL)
2131 return (-1);
2132
2133 p = ftpfs_translate_path (me, super, rpath);
2134 r = ftpfs_command (me, super, WAIT_REPLY, cmd, p);
2135 g_free (p);
2136 vfs_stamp_create (vfs_ftpfs_ops, super);
2137 if ((flags & OPT_IGNORE_ERROR) != 0)
2138 r = COMPLETE;
2139 if (r != COMPLETE)
2140 {
2141 me->verrno = EPERM;
2142 return (-1);
2143 }
2144 if (flush_directory_cache)
2145 vfs_s_invalidate (me, super);
2146 return 0;
2147 }
2148
2149
2150
2151 static int
2152 ftpfs_stat (const vfs_path_t *vpath, struct stat *buf)
2153 {
2154 int ret;
2155
2156 ret = vfs_s_stat (vpath, buf);
2157 ftpfs_set_blksize (buf);
2158 return ret;
2159 }
2160
2161
2162
2163 static int
2164 ftpfs_lstat (const vfs_path_t *vpath, struct stat *buf)
2165 {
2166 int ret;
2167
2168 ret = vfs_s_lstat (vpath, buf);
2169 ftpfs_set_blksize (buf);
2170 return ret;
2171 }
2172
2173
2174
2175 static int
2176 ftpfs_fstat (void *vfs_info, struct stat *buf)
2177 {
2178 int ret;
2179
2180 ret = vfs_s_fstat (vfs_info, buf);
2181 ftpfs_set_blksize (buf);
2182 return ret;
2183 }
2184
2185
2186
2187 static int
2188 ftpfs_chmod (const vfs_path_t *vpath, mode_t mode)
2189 {
2190 char buf[BUF_SMALL];
2191 int ret;
2192
2193 g_snprintf (buf, sizeof (buf), "SITE CHMOD %4.4o /%%s", (unsigned int) (mode & 07777));
2194 ret = ftpfs_send_command (vpath, buf, OPT_FLUSH);
2195 return ftpfs_ignore_chattr_errors ? 0 : ret;
2196 }
2197
2198
2199
2200 static int
2201 ftpfs_chown (const vfs_path_t *vpath, uid_t owner, gid_t group)
2202 {
2203 #if 0
2204 (void) vpath;
2205 (void) owner;
2206 (void) group;
2207
2208 me->verrno = EPERM;
2209 return (-1);
2210 #else
2211
2212
2213 (void) vpath;
2214 (void) owner;
2215 (void) group;
2216 return 0;
2217 #endif
2218 }
2219
2220
2221
2222 static int
2223 ftpfs_unlink (const vfs_path_t *vpath)
2224 {
2225 return ftpfs_send_command (vpath, "DELE /%s", OPT_FLUSH);
2226 }
2227
2228
2229
2230
2231 static gboolean
2232 ftpfs_is_same_dir (struct vfs_class *me, struct vfs_s_super *super, const char *path)
2233 {
2234 (void) me;
2235
2236 return (FTP_SUPER (super)->current_dir != NULL
2237 && strcmp (path, FTP_SUPER (super)->current_dir) == 0);
2238 }
2239
2240
2241
2242 static int
2243 ftpfs_chdir_internal (struct vfs_class *me, struct vfs_s_super *super, const char *remote_path)
2244 {
2245 ftp_super_t *ftp_super = FTP_SUPER (super);
2246 int r;
2247 char *p;
2248
2249 if (!ftp_super->cwd_deferred && ftpfs_is_same_dir (me, super, remote_path))
2250 return COMPLETE;
2251
2252 p = ftpfs_translate_path (me, super, remote_path);
2253 r = ftpfs_command (me, super, WAIT_REPLY, "CWD /%s", p);
2254 g_free (p);
2255
2256 if (r != COMPLETE)
2257 me->verrno = EIO;
2258 else
2259 {
2260 g_free (ftp_super->current_dir);
2261 ftp_super->current_dir = g_strdup (remote_path);
2262 ftp_super->cwd_deferred = FALSE;
2263 }
2264 return r;
2265 }
2266
2267
2268
2269 static int
2270 ftpfs_rename (const vfs_path_t *vpath1, const vfs_path_t *vpath2)
2271 {
2272 ftpfs_send_command (vpath1, "RNFR /%s", OPT_FLUSH);
2273 return ftpfs_send_command (vpath2, "RNTO /%s", OPT_FLUSH);
2274 }
2275
2276
2277
2278 static int
2279 ftpfs_mkdir (const vfs_path_t *vpath, mode_t mode)
2280 {
2281 (void) mode;
2282
2283 return ftpfs_send_command (vpath, "MKD /%s", OPT_FLUSH);
2284 }
2285
2286
2287
2288 static int
2289 ftpfs_rmdir (const vfs_path_t *vpath)
2290 {
2291 return ftpfs_send_command (vpath, "RMD /%s", OPT_FLUSH);
2292 }
2293
2294
2295
2296 static vfs_file_handler_t *
2297 ftpfs_fh_new (struct vfs_s_inode *ino, gboolean changed)
2298 {
2299 ftp_file_handler_t *fh;
2300
2301 fh = g_new0 (ftp_file_handler_t, 1);
2302 vfs_s_init_fh (VFS_FILE_HANDLER (fh), ino, changed);
2303 fh->sock = -1;
2304
2305 return VFS_FILE_HANDLER (fh);
2306 }
2307
2308
2309
2310 static int
2311 ftpfs_fh_open (struct vfs_class *me, vfs_file_handler_t *fh, int flags, mode_t mode)
2312 {
2313 ftp_file_handler_t *ftp = FTP_FILE_HANDLER (fh);
2314
2315 (void) mode;
2316
2317
2318 if (((flags & O_WRONLY) == O_WRONLY) && ((flags & (O_RDONLY | O_RDWR)) == 0))
2319 {
2320 #ifdef HAVE_STRUCT_LINGER_L_LINGER
2321 struct linger li;
2322 #else
2323 int li = 1;
2324 #endif
2325 char *name;
2326
2327
2328
2329
2330
2331 if (FTP_SUPER (VFS_FILE_HANDLER_SUPER (fh))->ctl_connection_busy)
2332 {
2333 if (fh->ino->localname == NULL)
2334 {
2335 vfs_path_t *vpath;
2336 int handle;
2337
2338 handle = vfs_mkstemps (&vpath, me->name, fh->ino->ent->name);
2339 if (handle == -1)
2340 return (-1);
2341
2342 close (handle);
2343 fh->ino->localname = vfs_path_free (vpath, FALSE);
2344 ftp->append = (flags & O_APPEND) != 0;
2345 }
2346 return 0;
2347 }
2348 name = vfs_s_fullpath (me, fh->ino);
2349 if (name == NULL)
2350 return (-1);
2351
2352 fh->handle = ftpfs_open_data_connection (me, VFS_FILE_HANDLER_SUPER (fh),
2353 (flags & O_APPEND) != 0 ? "APPE" : "STOR", name,
2354 TYPE_BINARY, 0);
2355 g_free (name);
2356
2357 if (fh->handle < 0)
2358 return (-1);
2359
2360 #ifdef HAVE_STRUCT_LINGER_L_LINGER
2361 li.l_onoff = 1;
2362 li.l_linger = 120;
2363 #endif
2364 setsockopt (fh->handle, SOL_SOCKET, SO_LINGER, &li, sizeof (li));
2365
2366 if (fh->ino->localname != NULL)
2367 {
2368 unlink (fh->ino->localname);
2369 MC_PTR_FREE (fh->ino->localname);
2370 }
2371 return 0;
2372 }
2373
2374 if (fh->ino->localname == NULL && vfs_s_retrieve_file (me, fh->ino) == -1)
2375 return (-1);
2376
2377 if (fh->ino->localname == NULL)
2378 vfs_die ("retrieve_file failed to fill in localname");
2379 return 0;
2380 }
2381
2382
2383
2384 static int
2385 ftpfs_fh_close (struct vfs_class *me, vfs_file_handler_t *fh)
2386 {
2387 if (fh->handle != -1 && fh->ino->localname == NULL)
2388 {
2389 ftp_super_t *ftp = FTP_SUPER (VFS_FILE_HANDLER_SUPER (fh));
2390
2391 close (fh->handle);
2392 fh->handle = -1;
2393 ftp->ctl_connection_busy = FALSE;
2394
2395
2396
2397 fh->changed = FALSE;
2398 if (ftpfs_get_reply (me, ftp->sock, NULL, 0) != COMPLETE)
2399 ERRNOR (EIO, -1);
2400 vfs_s_invalidate (me, VFS_FILE_HANDLER_SUPER (fh));
2401 }
2402
2403 return 0;
2404 }
2405
2406
2407
2408 static void
2409 ftpfs_done (struct vfs_class *me)
2410 {
2411 (void) me;
2412
2413 g_slist_free_full (no_proxy, g_free);
2414
2415 g_free (ftpfs_anonymous_passwd);
2416 g_free (ftpfs_proxy_host);
2417 }
2418
2419
2420
2421 static void
2422 ftpfs_fill_names (struct vfs_class *me, fill_names_f func)
2423 {
2424 GList *iter;
2425
2426 for (iter = VFS_SUBCLASS (me)->supers; iter != NULL; iter = g_list_next (iter))
2427 {
2428 const struct vfs_s_super *super = (const struct vfs_s_super *) iter->data;
2429 GString *name;
2430
2431 name = vfs_path_element_build_pretty_path_str (super->path_element);
2432
2433 func (name->str);
2434 g_string_free (name, TRUE);
2435 }
2436 }
2437
2438
2439
2440 static keyword_t
2441 ftpfs_netrc_next (void)
2442 {
2443 char *p;
2444 keyword_t i;
2445 static const char *const keywords[] = {
2446 "default", "machine", "login", "password", "passwd", "account", "macdef", NULL,
2447 };
2448
2449 while (TRUE)
2450 {
2451 netrcp = skip_separators (netrcp);
2452 if (*netrcp != '\n')
2453 break;
2454 netrcp++;
2455 }
2456 if (*netrcp == '\0')
2457 return NETRC_NONE;
2458
2459 p = buffer;
2460 if (*netrcp == '"')
2461 {
2462 for (netrcp++; *netrcp != '"' && *netrcp != '\0'; netrcp++)
2463 {
2464 if (*netrcp == '\\')
2465 netrcp++;
2466 *p++ = *netrcp;
2467 }
2468 }
2469 else
2470 {
2471 for (; *netrcp != '\0' && !whiteness (*netrcp) && *netrcp != ','; netrcp++)
2472 {
2473 if (*netrcp == '\\')
2474 netrcp++;
2475 *p++ = *netrcp;
2476 }
2477 }
2478
2479 *p = '\0';
2480 if (*buffer == '\0')
2481 return NETRC_NONE;
2482
2483 for (i = NETRC_DEFAULT; keywords[i - 1] != NULL; i++)
2484 if (strcmp (keywords[i - 1], buffer) == 0)
2485 return i;
2486
2487 return NETRC_UNKNOWN;
2488 }
2489
2490
2491
2492 static gboolean
2493 ftpfs_netrc_bad_mode (const char *netrcname)
2494 {
2495 struct stat mystat;
2496
2497 if (stat (netrcname, &mystat) >= 0 && (mystat.st_mode & 077) != 0)
2498 {
2499 static gboolean be_angry = TRUE;
2500
2501 if (be_angry)
2502 {
2503 message (D_ERROR, MSG_ERROR,
2504 _ ("~/.netrc file has incorrect mode\nRemove password or correct mode"));
2505 be_angry = FALSE;
2506 }
2507 return TRUE;
2508 }
2509
2510 return FALSE;
2511 }
2512
2513
2514
2515
2516
2517
2518
2519 static gboolean
2520 ftpfs_find_machine (const char *host, const char *domain)
2521 {
2522 keyword_t keyword;
2523
2524 if (host == NULL)
2525 host = "";
2526 if (domain == NULL)
2527 domain = "";
2528
2529 while ((keyword = ftpfs_netrc_next ()) != NETRC_NONE)
2530 {
2531 if (keyword == NETRC_DEFAULT)
2532 return TRUE;
2533
2534 if (keyword == NETRC_MACDEF)
2535 {
2536
2537 do
2538 {
2539 while (*netrcp != '\0' && *netrcp != '\n')
2540 netrcp++;
2541 if (*netrcp != '\n')
2542 break;
2543 netrcp++;
2544 }
2545 while (*netrcp != '\0' && *netrcp != '\n');
2546
2547 continue;
2548 }
2549
2550 if (keyword != NETRC_MACHINE)
2551 continue;
2552
2553
2554 if (ftpfs_netrc_next () == NETRC_NONE)
2555 break;
2556
2557 if (g_ascii_strcasecmp (host, buffer) != 0)
2558 {
2559 const char *host_domain;
2560
2561
2562 host_domain = strchr (host, '.');
2563 if (host_domain == NULL)
2564 continue;
2565
2566
2567 if (g_ascii_strcasecmp (host_domain, domain) != 0)
2568 continue;
2569
2570
2571 if (g_ascii_strncasecmp (host, buffer, host_domain - host) != 0)
2572 continue;
2573 }
2574
2575 return TRUE;
2576 }
2577
2578
2579 return FALSE;
2580 }
2581
2582
2583
2584
2585
2586
2587 static gboolean
2588 ftpfs_netrc_lookup (const char *host, char **login, char **pass)
2589 {
2590 char *netrcname;
2591 char *tmp_pass = NULL;
2592 char hostname[MAXHOSTNAMELEN];
2593 const char *domain;
2594 static struct rupcache
2595 {
2596 struct rupcache *next;
2597 char *host;
2598 char *login;
2599 char *pass;
2600 } *rup_cache = NULL, *rupp;
2601
2602
2603 MC_PTR_FREE (*login);
2604 MC_PTR_FREE (*pass);
2605
2606
2607 for (rupp = rup_cache; rupp != NULL; rupp = rupp->next)
2608 if (strcmp (host, rupp->host) == 0)
2609 {
2610 *login = g_strdup (rupp->login);
2611 *pass = g_strdup (rupp->pass);
2612 return TRUE;
2613 }
2614
2615
2616 netrcname = g_build_filename (mc_config_get_home_dir (), ".netrc", (char *) NULL);
2617 if (!g_file_get_contents (netrcname, &netrc, NULL, NULL))
2618 {
2619 g_free (netrcname);
2620 return TRUE;
2621 }
2622
2623 netrcp = netrc;
2624
2625
2626 if (gethostname (hostname, sizeof (hostname)) < 0)
2627 *hostname = '\0';
2628
2629 domain = strchr (hostname, '.');
2630 if (domain == NULL)
2631 domain = "";
2632
2633
2634 ftpfs_find_machine (host, domain);
2635
2636
2637 while (TRUE)
2638 {
2639 keyword_t keyword;
2640
2641 gboolean need_break = FALSE;
2642 keyword = ftpfs_netrc_next ();
2643
2644 switch (keyword)
2645 {
2646 case NETRC_LOGIN:
2647 if (ftpfs_netrc_next () == NETRC_NONE)
2648 {
2649 need_break = TRUE;
2650 break;
2651 }
2652
2653
2654 if (*login != NULL)
2655 {
2656 need_break = TRUE;
2657 break;
2658 }
2659
2660
2661 *login = g_strdup (buffer);
2662 break;
2663
2664 case NETRC_PASSWORD:
2665 case NETRC_PASSWD:
2666 if (ftpfs_netrc_next () == NETRC_NONE)
2667 {
2668 need_break = TRUE;
2669 break;
2670 }
2671
2672
2673 if (*login != NULL && strcmp (*login, "anonymous") != 0 && strcmp (*login, "ftp") != 0
2674 && ftpfs_netrc_bad_mode (netrcname))
2675 {
2676 need_break = TRUE;
2677 break;
2678 }
2679
2680
2681 if (tmp_pass == NULL)
2682 tmp_pass = g_strdup (buffer);
2683 break;
2684
2685 case NETRC_ACCOUNT:
2686
2687 if (ftpfs_netrc_next () == NETRC_NONE)
2688 {
2689 need_break = TRUE;
2690 break;
2691 }
2692
2693
2694 ftpfs_netrc_bad_mode (netrcname);
2695 break;
2696
2697 default:
2698
2699 need_break = TRUE;
2700 break;
2701 }
2702
2703 if (need_break)
2704 break;
2705 }
2706
2707 MC_PTR_FREE (netrc);
2708 g_free (netrcname);
2709
2710 rupp = g_new (struct rupcache, 1);
2711 rupp->host = g_strdup (host);
2712 rupp->login = g_strdup (*login);
2713 rupp->pass = g_strdup (tmp_pass);
2714
2715 rupp->next = rup_cache;
2716 rup_cache = rupp;
2717
2718 *pass = tmp_pass;
2719
2720 return TRUE;
2721 }
2722
2723
2724
2725
2726
2727
2728 void
2729 ftpfs_init_passwd (void)
2730 {
2731 ftpfs_anonymous_passwd = load_anon_passwd ();
2732
2733 if (ftpfs_anonymous_passwd == NULL)
2734 {
2735
2736
2737
2738
2739
2740
2741
2742
2743 ftpfs_anonymous_passwd = g_strdup ("anonymous@");
2744 }
2745 }
2746
2747
2748
2749 static int
2750 ftpfs_utime (const vfs_path_t *vpath, mc_timesbuf_t *times)
2751 {
2752 char buf[BUF_SMALL];
2753 mc_timespec_t atime, mtime;
2754 struct tm *tm;
2755
2756 vfs_get_timespecs_from_timesbuf (times, &atime, &mtime);
2757 tm = gmtime (&mtime.tv_sec);
2758
2759 g_snprintf (buf, sizeof (buf), "MFMT %04d%02d%02d%02d%02d%02d /%%s", tm->tm_year + 1900,
2760 tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
2761
2762 return ftpfs_send_command (vpath, buf, OPT_FLUSH);
2763 }
2764
2765
2766
2767 void
2768 vfs_init_ftpfs (void)
2769 {
2770 tcp_init ();
2771
2772 vfs_init_subclass (&ftpfs_subclass, "ftpfs", VFSF_NOLINKS | VFSF_REMOTE | VFSF_USETMP, "ftp");
2773 vfs_ftpfs_ops->done = ftpfs_done;
2774 vfs_ftpfs_ops->fill_names = ftpfs_fill_names;
2775 vfs_ftpfs_ops->stat = ftpfs_stat;
2776 vfs_ftpfs_ops->lstat = ftpfs_lstat;
2777 vfs_ftpfs_ops->fstat = ftpfs_fstat;
2778 vfs_ftpfs_ops->chmod = ftpfs_chmod;
2779 vfs_ftpfs_ops->chown = ftpfs_chown;
2780 vfs_ftpfs_ops->unlink = ftpfs_unlink;
2781 vfs_ftpfs_ops->rename = ftpfs_rename;
2782 vfs_ftpfs_ops->mkdir = ftpfs_mkdir;
2783 vfs_ftpfs_ops->rmdir = ftpfs_rmdir;
2784 vfs_ftpfs_ops->ctl = ftpfs_ctl;
2785 vfs_ftpfs_ops->utime = ftpfs_utime;
2786 ftpfs_subclass.archive_same = ftpfs_archive_same;
2787 ftpfs_subclass.new_archive = ftpfs_new_archive;
2788 ftpfs_subclass.open_archive = ftpfs_open_archive;
2789 ftpfs_subclass.free_archive = ftpfs_free_archive;
2790 ftpfs_subclass.fh_new = ftpfs_fh_new;
2791 ftpfs_subclass.fh_open = ftpfs_fh_open;
2792 ftpfs_subclass.fh_close = ftpfs_fh_close;
2793 ftpfs_subclass.dir_load = ftpfs_dir_load;
2794 ftpfs_subclass.file_store = ftpfs_file_store;
2795 ftpfs_subclass.linear_start = ftpfs_linear_start;
2796 ftpfs_subclass.linear_read = ftpfs_linear_read;
2797 ftpfs_subclass.linear_close = ftpfs_linear_close;
2798 vfs_register_class (vfs_ftpfs_ops);
2799 }
2800
2801