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