ftpfs.c 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019
  1. /* Virtual File System: FTP file system.
  2. Copyright (C) 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
  3. 2006, 2007 Free Software Foundation, Inc.
  4. Written by: 1995 Ching Hui
  5. 1995 Jakub Jelinek
  6. 1995, 1996, 1997 Miguel de Icaza
  7. 1997 Norbert Warmuth
  8. 1998 Pavel Machek
  9. This program is free software; you can redistribute it and/or
  10. modify it under the terms of the GNU Library General Public License
  11. as published by the Free Software Foundation; either version 2 of
  12. the License, or (at your option) any later version.
  13. This program is distributed in the hope that it will be useful,
  14. but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. GNU Library General Public License for more details.
  17. You should have received a copy of the GNU Library General Public
  18. License along with this program; if not, write to the Free Software
  19. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
  20. /* FTPfs TODO:
  21. - make it more robust - all the connects etc. should handle EADDRINUSE and
  22. ERETRY (have I spelled these names correctly?)
  23. - make the user able to flush a connection - all the caches will get empty
  24. etc., (tarfs as well), we should give there a user selectable timeout
  25. and assign a key sequence.
  26. - use hash table instead of linklist to cache ftpfs directory.
  27. What to do with this?
  28. * NOTE: Usage of tildes is deprecated, consider:
  29. * cd /#ftp:pavel@hobit
  30. * cd ~
  31. * And now: what do I want to do? Do I want to go to /home/pavel or to
  32. * /#ftp:hobit/home/pavel? I think first has better sense...
  33. *
  34. {
  35. int f = !strcmp( remote_path, "/~" );
  36. if (f || !strncmp( remote_path, "/~/", 3 )) {
  37. char *s;
  38. s = concat_dir_and_file( qhome (*bucket), remote_path +3-f );
  39. g_free (remote_path);
  40. remote_path = s;
  41. }
  42. }
  43. */
  44. /* Namespace pollution: horrible */
  45. #include <config.h>
  46. #include <sys/types.h> /* POSIX-required by sys/socket.h and netdb.h */
  47. #include <netdb.h> /* struct hostent */
  48. #include <sys/socket.h> /* AF_INET */
  49. #include <netinet/in.h> /* struct in_addr */
  50. #ifdef HAVE_ARPA_INET_H
  51. #include <arpa/inet.h>
  52. #endif
  53. #include <arpa/ftp.h>
  54. #include <arpa/telnet.h>
  55. #include <sys/param.h>
  56. #include <errno.h>
  57. #include <ctype.h>
  58. #include "../src/global.h"
  59. #include "../src/tty.h" /* enable/disable interrupt key */
  60. #include "../src/wtools.h" /* message() */
  61. #include "../src/main.h" /* print_vfs_message */
  62. #include "../src/history.h"
  63. #include "utilvfs.h"
  64. #include "xdirentry.h"
  65. #include "vfs.h"
  66. #include "vfs-impl.h"
  67. #include "gc.h" /* vfs_stamp_create */
  68. #include "tcputil.h"
  69. #include "../src/setup.h" /* for load_anon_passwd */
  70. #include "ftpfs.h"
  71. #ifndef MAXHOSTNAMELEN
  72. # define MAXHOSTNAMELEN 64
  73. #endif
  74. #define UPLOAD_ZERO_LENGTH_FILE
  75. #define SUP super->u.ftp
  76. #define FH_SOCK fh->u.ftp.sock
  77. #ifndef INADDR_NONE
  78. #define INADDR_NONE 0xffffffff
  79. #endif
  80. #define RFC_AUTODETECT 0
  81. #define RFC_DARING 1
  82. #define RFC_STRICT 2
  83. #ifndef HAVE_SOCKLEN_T
  84. typedef int socklen_t;
  85. #endif
  86. static int ftpfs_errno;
  87. static int code;
  88. /* Delay to retry a connection */
  89. int ftpfs_retry_seconds = 30;
  90. /* Method to use to connect to ftp sites */
  91. int ftpfs_use_passive_connections = 1;
  92. int ftpfs_use_passive_connections_over_proxy = 0;
  93. /* Method used to get directory listings:
  94. * 1: try 'LIST -la <path>', if it fails
  95. * fall back to CWD <path>; LIST
  96. * 0: always use CWD <path>; LIST
  97. */
  98. int ftpfs_use_unix_list_options = 1;
  99. /* First "CWD <path>", then "LIST -la ." */
  100. int ftpfs_first_cd_then_ls = 1;
  101. /* Use the ~/.netrc */
  102. int use_netrc = 1;
  103. /* Anonymous setup */
  104. char *ftpfs_anonymous_passwd = NULL;
  105. int ftpfs_directory_timeout = 900;
  106. /* Proxy host */
  107. char *ftpfs_proxy_host = NULL;
  108. /* wether we have to use proxy by default? */
  109. int ftpfs_always_use_proxy;
  110. #ifdef FIXME_LATER_ALIGATOR
  111. static struct linklist *connections_list;
  112. #endif
  113. /* ftpfs_command wait_flag: */
  114. #define NONE 0x00
  115. #define WAIT_REPLY 0x01
  116. #define WANT_STRING 0x02
  117. static char reply_str [80];
  118. static struct vfs_class vfs_ftpfs_ops;
  119. /* char *ftpfs_translate_path (struct ftpfs_connection *bucket, char *remote_path)
  120. Translate a Unix path, i.e. MC's internal path representation (e.g.
  121. /somedir/somefile) to a path valid for the remote server. Every path
  122. transfered to the remote server has to be mangled by this function
  123. right prior to sending it.
  124. Currently only Amiga ftp servers are handled in a special manner.
  125. When the remote server is an amiga:
  126. a) strip leading slash if necesarry
  127. b) replace first occurance of ":/" with ":"
  128. c) strip trailing "/."
  129. */
  130. static char *ftpfs_get_current_directory (struct vfs_class *me, struct vfs_s_super *super);
  131. static int ftpfs_chdir_internal (struct vfs_class *me, struct vfs_s_super *super, const char *remote_path);
  132. static int ftpfs_command (struct vfs_class *me, struct vfs_s_super *super, int wait_reply, const char *fmt, ...)
  133. __attribute__ ((format (__printf__, 4, 5)));
  134. static int ftpfs_open_socket (struct vfs_class *me, struct vfs_s_super *super);
  135. static int ftpfs_login_server (struct vfs_class *me, struct vfs_s_super *super, const char *netrcpass);
  136. static int ftpfs_netrc_lookup (const char *host, char **login, char **pass);
  137. static char *
  138. ftpfs_translate_path (struct vfs_class *me, struct vfs_s_super *super, const char *remote_path)
  139. {
  140. if (!SUP.remote_is_amiga)
  141. return g_strdup (remote_path);
  142. else {
  143. char *ret, *p;
  144. if (MEDATA->logfile) {
  145. fprintf (MEDATA->logfile, "MC -- ftpfs_translate_path: %s\n", remote_path);
  146. fflush (MEDATA->logfile);
  147. }
  148. /* strip leading slash(es) */
  149. while (*remote_path == '/')
  150. remote_path++;
  151. /*
  152. * Don't change "/" into "", e.g. "CWD " would be
  153. * invalid.
  154. */
  155. if (*remote_path == '\0')
  156. return g_strdup (".");
  157. ret = g_strdup (remote_path);
  158. /* replace first occurance of ":/" with ":" */
  159. if ((p = strchr (ret, ':')) && *(p + 1) == '/')
  160. strcpy (p + 1, p + 2);
  161. /* strip trailing "/." */
  162. if ((p = strrchr (ret, '/')) && *(p + 1) == '.' && *(p + 2) == '\0')
  163. *p = '\0';
  164. return ret;
  165. }
  166. }
  167. /* Extract the hostname and username from the path */
  168. /*
  169. * path is in the form: [user@]hostname:port/remote-dir, e.g.:
  170. * ftp://sunsite.unc.edu/pub/linux
  171. * ftp://miguel@sphinx.nuclecu.unam.mx/c/nc
  172. * ftp://tsx-11.mit.edu:8192/
  173. * ftp://joe@foo.edu:11321/private
  174. * If the user is empty, e.g. ftp://@roxanne/private, then your login name
  175. * is supplied.
  176. *
  177. */
  178. #define FTP_COMMAND_PORT 21
  179. static void
  180. ftpfs_split_url(char *path, char **host, char **user, int *port, char **pass)
  181. {
  182. char *p;
  183. p = vfs_split_url (path, host, user, port, pass, FTP_COMMAND_PORT,
  184. URL_ALLOW_ANON);
  185. if (!*user) {
  186. /* Look up user and password in netrc */
  187. if (use_netrc)
  188. ftpfs_netrc_lookup (*host, user, pass);
  189. if (!*user)
  190. *user = g_strdup ("anonymous");
  191. }
  192. /* Look up password in netrc for known user */
  193. if (use_netrc && *user && pass && !*pass) {
  194. char *new_user;
  195. ftpfs_netrc_lookup (*host, &new_user, pass);
  196. /* If user is different, remove password */
  197. if (new_user && strcmp (*user, new_user)) {
  198. g_free (*pass);
  199. *pass = NULL;
  200. }
  201. g_free (new_user);
  202. }
  203. g_free (p);
  204. }
  205. /* Returns a reply code, check /usr/include/arpa/ftp.h for possible values */
  206. static int
  207. ftpfs_get_reply (struct vfs_class *me, int sock, char *string_buf, int string_len)
  208. {
  209. char answer[BUF_1K];
  210. int i;
  211. for (;;) {
  212. if (!vfs_s_get_line (me, sock, answer, sizeof (answer), '\n')){
  213. if (string_buf)
  214. *string_buf = 0;
  215. code = 421;
  216. return 4;
  217. }
  218. switch (sscanf(answer, "%d", &code)){
  219. case 0:
  220. if (string_buf)
  221. g_strlcpy (string_buf, answer, string_len);
  222. code = 500;
  223. return 5;
  224. case 1:
  225. if (answer[3] == '-') {
  226. while (1) {
  227. if (!vfs_s_get_line (me, sock, answer, sizeof(answer), '\n')){
  228. if (string_buf)
  229. *string_buf = 0;
  230. code = 421;
  231. return 4;
  232. }
  233. if ((sscanf (answer, "%d", &i) > 0) &&
  234. (code == i) && (answer[3] == ' '))
  235. break;
  236. }
  237. }
  238. if (string_buf)
  239. g_strlcpy (string_buf, answer, string_len);
  240. return code / 100;
  241. }
  242. }
  243. }
  244. static int
  245. ftpfs_reconnect (struct vfs_class *me, struct vfs_s_super *super)
  246. {
  247. int sock = ftpfs_open_socket (me, super);
  248. if (sock != -1){
  249. char *cwdir = SUP.cwdir;
  250. close (SUP.sock);
  251. SUP.sock = sock;
  252. SUP.cwdir = NULL;
  253. if (ftpfs_login_server (me, super, SUP.password)){
  254. if (!cwdir)
  255. return 1;
  256. sock = ftpfs_chdir_internal (me, super, cwdir);
  257. g_free (cwdir);
  258. return sock == COMPLETE;
  259. }
  260. SUP.cwdir = cwdir;
  261. }
  262. return 0;
  263. }
  264. static int
  265. ftpfs_command (struct vfs_class *me, struct vfs_s_super *super, int wait_reply, const char *fmt, ...)
  266. {
  267. va_list ap;
  268. char *cmdstr;
  269. int status, cmdlen;
  270. static int retry = 0;
  271. static int level = 0; /* ftpfs_login_server() use ftpfs_command() */
  272. va_start (ap, fmt);
  273. cmdstr = g_strdup_vprintf (fmt, ap);
  274. va_end (ap);
  275. cmdlen = strlen (cmdstr);
  276. cmdstr = g_realloc (cmdstr, cmdlen + 3);
  277. strcpy (cmdstr + cmdlen, "\r\n");
  278. cmdlen += 2;
  279. if (MEDATA->logfile) {
  280. if (strncmp (cmdstr, "PASS ", 5) == 0) {
  281. fputs ("PASS <Password not logged>\r\n", MEDATA->logfile);
  282. } else
  283. fwrite (cmdstr, cmdlen, 1, MEDATA->logfile);
  284. fflush (MEDATA->logfile);
  285. }
  286. got_sigpipe = 0;
  287. enable_interrupt_key ();
  288. status = write (SUP.sock, cmdstr, cmdlen);
  289. if (status < 0) {
  290. code = 421;
  291. if (errno == EPIPE) { /* Remote server has closed connection */
  292. if (level == 0) {
  293. level = 1;
  294. status = ftpfs_reconnect (me, super);
  295. level = 0;
  296. if (status && (write (SUP.sock, cmdstr, cmdlen) > 0)) {
  297. goto ok;
  298. }
  299. }
  300. got_sigpipe = 1;
  301. }
  302. g_free (cmdstr);
  303. disable_interrupt_key ();
  304. return TRANSIENT;
  305. }
  306. retry = 0;
  307. ok:
  308. disable_interrupt_key ();
  309. if (wait_reply)
  310. {
  311. status = ftpfs_get_reply (me, SUP.sock,
  312. (wait_reply & WANT_STRING) ? reply_str : NULL,
  313. sizeof (reply_str) - 1);
  314. if ((wait_reply & WANT_STRING) && !retry && !level && code == 421)
  315. {
  316. retry = 1;
  317. level = 1;
  318. status = ftpfs_reconnect (me, super);
  319. level = 0;
  320. if (status && (write (SUP.sock, cmdstr, cmdlen) > 0)) {
  321. goto ok;
  322. }
  323. }
  324. retry = 0;
  325. g_free (cmdstr);
  326. return status;
  327. }
  328. g_free (cmdstr);
  329. return COMPLETE;
  330. }
  331. static void
  332. ftpfs_free_archive (struct vfs_class *me, struct vfs_s_super *super)
  333. {
  334. if (SUP.sock != -1){
  335. print_vfs_message (_("ftpfs: Disconnecting from %s"), SUP.host);
  336. ftpfs_command(me, super, NONE, "QUIT");
  337. close(SUP.sock);
  338. }
  339. g_free (SUP.host);
  340. g_free (SUP.user);
  341. g_free (SUP.cwdir);
  342. g_free (SUP.password);
  343. }
  344. /* some defines only used by ftpfs_changetype */
  345. /* These two are valid values for the second parameter */
  346. #define TYPE_ASCII 0
  347. #define TYPE_BINARY 1
  348. /* This one is only used to initialize bucket->isbinary, don't use it as
  349. second parameter to ftpfs_changetype. */
  350. #define TYPE_UNKNOWN -1
  351. static int
  352. ftpfs_changetype (struct vfs_class *me, struct vfs_s_super *super, int binary)
  353. {
  354. if (binary != SUP.isbinary) {
  355. if (ftpfs_command (me, super, WAIT_REPLY, "TYPE %c", binary ? 'I' : 'A') != COMPLETE)
  356. ERRNOR (EIO, -1);
  357. SUP.isbinary = binary;
  358. }
  359. return binary;
  360. }
  361. /* This routine logs the user in */
  362. static int
  363. ftpfs_login_server (struct vfs_class *me, struct vfs_s_super *super,
  364. const char *netrcpass)
  365. {
  366. char *pass;
  367. char *op;
  368. char *name; /* login user name */
  369. int anon = 0;
  370. char reply_string[BUF_MEDIUM];
  371. SUP.isbinary = TYPE_UNKNOWN;
  372. if (SUP.password) /* explicit password */
  373. op = g_strdup (SUP.password);
  374. else if (netrcpass) /* password from netrc */
  375. op = g_strdup (netrcpass);
  376. else if (!strcmp (SUP.user, "anonymous") || !strcmp (SUP.user, "ftp")) {
  377. if (!ftpfs_anonymous_passwd) /* default anonymous password */
  378. ftpfs_init_passwd ();
  379. op = g_strdup (ftpfs_anonymous_passwd);
  380. anon = 1;
  381. } else { /* ask user */
  382. char *p;
  383. p = g_strconcat (_(" FTP: Password required for "), SUP.user, " ",
  384. NULL);
  385. op = vfs_get_password (p);
  386. g_free (p);
  387. if (op == NULL)
  388. ERRNOR (EPERM, 0);
  389. SUP.password = g_strdup (op);
  390. }
  391. if (!anon || MEDATA->logfile)
  392. pass = op;
  393. else {
  394. pass = g_strconcat ("-", op, (char *) NULL);
  395. wipe_password (op);
  396. }
  397. /* Proxy server accepts: username@host-we-want-to-connect */
  398. if (SUP.proxy) {
  399. name =
  400. g_strconcat (SUP.user, "@",
  401. SUP.host[0] == '!' ? SUP.host + 1 : SUP.host,
  402. NULL);
  403. } else
  404. name = g_strdup (SUP.user);
  405. if (ftpfs_get_reply
  406. (me, SUP.sock, reply_string,
  407. sizeof (reply_string) - 1) == COMPLETE) {
  408. g_strup (reply_string);
  409. SUP.remote_is_amiga = strstr (reply_string, "AMIGA") != 0;
  410. if (MEDATA->logfile) {
  411. fprintf (MEDATA->logfile, "MC -- remote_is_amiga = %d\n",
  412. SUP.remote_is_amiga);
  413. fflush (MEDATA->logfile);
  414. }
  415. print_vfs_message (_("ftpfs: sending login name"));
  416. switch (ftpfs_command (me, super, WAIT_REPLY, "USER %s", name)) {
  417. case CONTINUE:
  418. print_vfs_message (_("ftpfs: sending user password"));
  419. code = ftpfs_command (me, super, WAIT_REPLY, "PASS %s", pass);
  420. if (code == CONTINUE) {
  421. char *p;
  422. p = g_strdup_printf (_
  423. ("FTP: Account required for user %s"),
  424. SUP.user);
  425. op = input_dialog (p, _("Account:"), MC_HISTORY_FTPFS_ACCOUNT, "");
  426. g_free (p);
  427. if (op == NULL)
  428. ERRNOR (EPERM, 0);
  429. print_vfs_message (_("ftpfs: sending user account"));
  430. code =
  431. ftpfs_command (me, super, WAIT_REPLY, "ACCT %s", op);
  432. g_free (op);
  433. }
  434. if (code != COMPLETE)
  435. break;
  436. /* fall through */
  437. case COMPLETE:
  438. print_vfs_message (_("ftpfs: logged in"));
  439. wipe_password (pass);
  440. g_free (name);
  441. return 1;
  442. default:
  443. SUP.failed_on_login = 1;
  444. if (SUP.password)
  445. wipe_password (SUP.password);
  446. SUP.password = 0;
  447. goto login_fail;
  448. }
  449. }
  450. message (1, MSG_ERROR, _("ftpfs: Login incorrect for user %s "),
  451. SUP.user);
  452. login_fail:
  453. wipe_password (pass);
  454. g_free (name);
  455. ERRNOR (EPERM, 0);
  456. }
  457. static struct no_proxy_entry {
  458. char *domain;
  459. void *next;
  460. } *no_proxy;
  461. static void
  462. ftpfs_load_no_proxy_list (void)
  463. {
  464. /* FixMe: shouldn't be hardcoded!!! */
  465. char s[BUF_LARGE]; /* provide for BUF_LARGE characters */
  466. struct no_proxy_entry *np, *current = 0;
  467. FILE *npf;
  468. int c;
  469. char *p;
  470. static char *mc_file;
  471. if (mc_file)
  472. return;
  473. mc_file = concat_dir_and_file (mc_home, "mc.no_proxy");
  474. if (exist_file (mc_file) &&
  475. (npf = fopen (mc_file, "r"))) {
  476. while (fgets (s, sizeof (s), npf)) {
  477. if (!(p = strchr (s, '\n'))) { /* skip bogus entries */
  478. while ((c = fgetc (npf)) != EOF && c != '\n')
  479. ;
  480. continue;
  481. }
  482. if (p == s)
  483. continue;
  484. *p = '\0';
  485. np = g_new (struct no_proxy_entry, 1);
  486. np->domain = g_strdup (s);
  487. np->next = NULL;
  488. if (no_proxy)
  489. current->next = np;
  490. else
  491. no_proxy = np;
  492. current = np;
  493. }
  494. fclose (npf);
  495. }
  496. g_free (mc_file);
  497. }
  498. /* Return 1 if FTP proxy should be used for this host, 0 otherwise */
  499. static int
  500. ftpfs_check_proxy (const char *host)
  501. {
  502. struct no_proxy_entry *npe;
  503. if (!ftpfs_proxy_host || !*ftpfs_proxy_host || !host || !*host)
  504. return 0; /* sanity check */
  505. if (*host == '!')
  506. return 1;
  507. if (!ftpfs_always_use_proxy)
  508. return 0;
  509. if (!strchr (host, '.'))
  510. return 0;
  511. ftpfs_load_no_proxy_list ();
  512. for (npe = no_proxy; npe; npe=npe->next) {
  513. char *domain = npe->domain;
  514. if (domain[0] == '.') {
  515. int ld = strlen (domain);
  516. int lh = strlen (host);
  517. while (ld && lh && host[lh - 1] == domain[ld - 1]) {
  518. ld--;
  519. lh--;
  520. }
  521. if (!ld)
  522. return 0;
  523. } else
  524. if (!g_strcasecmp (host, domain))
  525. return 0;
  526. }
  527. return 1;
  528. }
  529. static void
  530. ftpfs_get_proxy_host_and_port (const char *proxy, char **host, int *port)
  531. {
  532. char *user, *dir;
  533. dir =
  534. vfs_split_url (proxy, host, &user, port, 0, FTP_COMMAND_PORT,
  535. URL_ALLOW_ANON);
  536. g_free (user);
  537. g_free (dir);
  538. }
  539. static int
  540. ftpfs_open_socket (struct vfs_class *me, struct vfs_s_super *super)
  541. {
  542. struct sockaddr_in server_address;
  543. struct hostent *hp;
  544. int my_socket;
  545. char *host;
  546. int port = SUP.port;
  547. int free_host = 0;
  548. (void) me;
  549. /* Use a proxy host? */
  550. host = SUP.host;
  551. if (!host || !*host){
  552. print_vfs_message (_("ftpfs: Invalid host name."));
  553. ftpfs_errno = EINVAL;
  554. return -1;
  555. }
  556. /* Hosts to connect to that start with a ! should use proxy */
  557. if (SUP.proxy){
  558. ftpfs_get_proxy_host_and_port (ftpfs_proxy_host, &host, &port);
  559. free_host = 1;
  560. }
  561. enable_interrupt_key(); /* clear the interrupt flag */
  562. /* Get host address */
  563. memset ((char *) &server_address, 0, sizeof (server_address));
  564. server_address.sin_family = AF_INET;
  565. server_address.sin_addr.s_addr = inet_addr (host);
  566. if (server_address.sin_addr.s_addr == INADDR_NONE) {
  567. hp = gethostbyname (host);
  568. if (hp == NULL){
  569. disable_interrupt_key();
  570. print_vfs_message (_("ftpfs: Invalid host address."));
  571. ftpfs_errno = EINVAL;
  572. if (free_host)
  573. g_free (host);
  574. return -1;
  575. }
  576. server_address.sin_family = hp->h_addrtype;
  577. /* We copy only 4 bytes, we cannot trust hp->h_length, as it comes from the DNS */
  578. memcpy ((char *) &server_address.sin_addr, (char *) hp->h_addr, 4);
  579. }
  580. server_address.sin_port = htons (port);
  581. /* Connect */
  582. if ((my_socket = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
  583. disable_interrupt_key();
  584. ftpfs_errno = errno;
  585. if (free_host)
  586. g_free (host);
  587. return -1;
  588. }
  589. print_vfs_message (_("ftpfs: making connection to %s"), host);
  590. if (free_host)
  591. g_free (host);
  592. if (connect (my_socket, (struct sockaddr *) &server_address,
  593. sizeof (server_address)) < 0){
  594. ftpfs_errno = errno;
  595. if (errno == EINTR && got_interrupt ())
  596. print_vfs_message (_("ftpfs: connection interrupted by user"));
  597. else
  598. print_vfs_message (_("ftpfs: connection to server failed: %s"),
  599. unix_error_string(errno));
  600. disable_interrupt_key();
  601. close (my_socket);
  602. return -1;
  603. }
  604. disable_interrupt_key();
  605. return my_socket;
  606. }
  607. static int
  608. ftpfs_open_archive_int (struct vfs_class *me, struct vfs_s_super *super)
  609. {
  610. int retry_seconds, count_down;
  611. /* We do not want to use the passive if we are using proxies */
  612. if (SUP.proxy)
  613. SUP.use_passive_connection = ftpfs_use_passive_connections_over_proxy;
  614. retry_seconds = 0;
  615. do {
  616. SUP.failed_on_login = 0;
  617. SUP.sock = ftpfs_open_socket (me, super);
  618. if (SUP.sock == -1)
  619. return -1;
  620. if (ftpfs_login_server (me, super, NULL)) {
  621. /* Logged in, no need to retry the connection */
  622. break;
  623. } else {
  624. if (SUP.failed_on_login){
  625. /* Close only the socket descriptor */
  626. close (SUP.sock);
  627. } else {
  628. return -1;
  629. }
  630. if (ftpfs_retry_seconds){
  631. retry_seconds = ftpfs_retry_seconds;
  632. enable_interrupt_key ();
  633. for (count_down = retry_seconds; count_down; count_down--){
  634. print_vfs_message (_("Waiting to retry... %d (Control-C to cancel)"), count_down);
  635. sleep (1);
  636. if (got_interrupt ()){
  637. /* ftpfs_errno = E; */
  638. disable_interrupt_key ();
  639. return 0;
  640. }
  641. }
  642. disable_interrupt_key ();
  643. }
  644. }
  645. } while (retry_seconds);
  646. SUP.cwdir = ftpfs_get_current_directory (me, super);
  647. if (!SUP.cwdir)
  648. SUP.cwdir = g_strdup (PATH_SEP_STR);
  649. return 0;
  650. }
  651. static int
  652. ftpfs_open_archive (struct vfs_class *me, struct vfs_s_super *super,
  653. const char *archive_name, char *op)
  654. {
  655. char *host, *user, *password;
  656. int port;
  657. (void) archive_name;
  658. ftpfs_split_url (strchr (op, ':') + 1, &host, &user, &port, &password);
  659. SUP.host = host;
  660. SUP.user = user;
  661. SUP.port = port;
  662. SUP.cwdir = NULL;
  663. SUP.proxy = 0;
  664. if (ftpfs_check_proxy (host))
  665. SUP.proxy = ftpfs_proxy_host;
  666. SUP.password = password;
  667. SUP.use_passive_connection = ftpfs_use_passive_connections;
  668. SUP.strict = ftpfs_use_unix_list_options ? RFC_AUTODETECT : RFC_STRICT;
  669. SUP.isbinary = TYPE_UNKNOWN;
  670. SUP.remote_is_amiga = 0;
  671. super->name = g_strdup ("/");
  672. super->root =
  673. vfs_s_new_inode (me, super,
  674. vfs_s_default_stat (me, S_IFDIR | 0755));
  675. return ftpfs_open_archive_int (me, super);
  676. }
  677. static int
  678. ftpfs_archive_same (struct vfs_class *me, struct vfs_s_super *super,
  679. const char *archive_name, char *op, void *cookie)
  680. {
  681. char *host, *user;
  682. int port;
  683. (void) me;
  684. (void) archive_name;
  685. (void) cookie;
  686. ftpfs_split_url (strchr (op, ':') + 1, &host, &user, &port, 0);
  687. port = ((strcmp (host, SUP.host) == 0)
  688. && (strcmp (user, SUP.user) == 0) && (port == SUP.port));
  689. g_free (host);
  690. g_free (user);
  691. return port;
  692. }
  693. /* The returned directory should always contain a trailing slash */
  694. static char *
  695. ftpfs_get_current_directory (struct vfs_class *me, struct vfs_s_super *super)
  696. {
  697. char buf[BUF_8K], *bufp, *bufq;
  698. if (ftpfs_command (me, super, NONE, "PWD") == COMPLETE &&
  699. ftpfs_get_reply(me, SUP.sock, buf, sizeof(buf)) == COMPLETE) {
  700. bufp = NULL;
  701. for (bufq = buf; *bufq; bufq++)
  702. if (*bufq == '"') {
  703. if (!bufp) {
  704. bufp = bufq + 1;
  705. } else {
  706. *bufq = 0;
  707. if (*bufp) {
  708. if (*(bufq - 1) != '/') {
  709. *bufq++ = '/';
  710. *bufq = 0;
  711. }
  712. if (*bufp == '/')
  713. return g_strdup (bufp);
  714. else {
  715. /* If the remote server is an Amiga a leading slash
  716. might be missing. MC needs it because it is used
  717. as separator between hostname and path internally. */
  718. return g_strconcat( "/", bufp, NULL);
  719. }
  720. } else {
  721. ftpfs_errno = EIO;
  722. return NULL;
  723. }
  724. }
  725. }
  726. }
  727. ftpfs_errno = EIO;
  728. return NULL;
  729. }
  730. /* Setup Passive ftp connection, we use it for source routed connections */
  731. static int
  732. ftpfs_setup_passive (struct vfs_class *me, struct vfs_s_super *super, int my_socket, struct sockaddr_in *sa)
  733. {
  734. int xa, xb, xc, xd, xe, xf;
  735. char n [6];
  736. char *c;
  737. if (ftpfs_command (me, super, WAIT_REPLY | WANT_STRING, "PASV") != COMPLETE)
  738. return 0;
  739. /* Parse remote parameters */
  740. for (c = reply_str + 4; (*c) && (!isdigit ((unsigned char) *c)); c++)
  741. ;
  742. if (!*c)
  743. return 0;
  744. if (!isdigit ((unsigned char) *c))
  745. return 0;
  746. if (sscanf (c, "%d,%d,%d,%d,%d,%d", &xa, &xb, &xc, &xd, &xe, &xf) != 6)
  747. return 0;
  748. n [0] = (unsigned char) xa;
  749. n [1] = (unsigned char) xb;
  750. n [2] = (unsigned char) xc;
  751. n [3] = (unsigned char) xd;
  752. n [4] = (unsigned char) xe;
  753. n [5] = (unsigned char) xf;
  754. memcpy (&(sa->sin_addr.s_addr), (void *)n, 4);
  755. memcpy (&(sa->sin_port), (void *)&n[4], 2);
  756. if (connect (my_socket, (struct sockaddr *) sa, sizeof (struct sockaddr_in)) < 0)
  757. return 0;
  758. return 1;
  759. }
  760. static int
  761. ftpfs_initconn (struct vfs_class *me, struct vfs_s_super *super)
  762. {
  763. struct sockaddr_in data_addr;
  764. int data;
  765. socklen_t len = sizeof(data_addr);
  766. struct protoent *pe;
  767. pe = getprotobyname ("tcp");
  768. if (pe == NULL)
  769. ERRNOR (EIO, -1);
  770. again:
  771. if (getsockname (SUP.sock, (struct sockaddr *) &data_addr, &len) == -1)
  772. ERRNOR (EIO, -1);
  773. data_addr.sin_port = 0;
  774. data = socket (AF_INET, SOCK_STREAM, pe->p_proto);
  775. if (data < 0)
  776. ERRNOR (EIO, -1);
  777. if (SUP.use_passive_connection) {
  778. if (ftpfs_setup_passive (me, super, data, &data_addr))
  779. return data;
  780. SUP.use_passive_connection = 0;
  781. print_vfs_message (_("ftpfs: could not setup passive mode"));
  782. /* data or data_addr may be damaged by ftpfs_setup_passive */
  783. close (data);
  784. goto again;
  785. }
  786. /* If passive setup fails, fallback to active connections */
  787. /* Active FTP connection */
  788. if ((bind (data, (struct sockaddr *)&data_addr, len) == 0) &&
  789. (getsockname (data, (struct sockaddr *) &data_addr, &len) == 0) &&
  790. (listen (data, 1) == 0))
  791. {
  792. unsigned char *a = (unsigned char *)&data_addr.sin_addr;
  793. unsigned char *p = (unsigned char *)&data_addr.sin_port;
  794. if (ftpfs_command (me, super, WAIT_REPLY, "PORT %d,%d,%d,%d,%d,%d", a[0], a[1],
  795. a[2], a[3], p[0], p[1]) == COMPLETE)
  796. return data;
  797. }
  798. close (data);
  799. ftpfs_errno = EIO;
  800. return -1;
  801. }
  802. static int
  803. ftpfs_open_data_connection (struct vfs_class *me, struct vfs_s_super *super, const char *cmd,
  804. const char *remote, int isbinary, int reget)
  805. {
  806. struct sockaddr_in from;
  807. int s, j, data;
  808. socklen_t fromlen = sizeof(from);
  809. if ((s = ftpfs_initconn (me, super)) == -1)
  810. return -1;
  811. if (ftpfs_changetype (me, super, isbinary) == -1)
  812. return -1;
  813. if (reget > 0){
  814. j = ftpfs_command (me, super, WAIT_REPLY, "REST %d", reget);
  815. if (j != CONTINUE)
  816. return -1;
  817. }
  818. if (remote) {
  819. char *remote_path = ftpfs_translate_path (me, super, remote);
  820. j = ftpfs_command (me, super, WAIT_REPLY, "%s /%s", cmd,
  821. /* WarFtpD can't STORE //filename */
  822. (*remote_path == '/') ? remote_path + 1 : remote_path);
  823. g_free (remote_path);
  824. } else
  825. j = ftpfs_command (me, super, WAIT_REPLY, "%s", cmd);
  826. if (j != PRELIM)
  827. ERRNOR (EPERM, -1);
  828. enable_interrupt_key();
  829. if (SUP.use_passive_connection)
  830. data = s;
  831. else {
  832. data = accept (s, (struct sockaddr *)&from, &fromlen);
  833. if (data < 0) {
  834. ftpfs_errno = errno;
  835. close (s);
  836. return -1;
  837. }
  838. close (s);
  839. }
  840. disable_interrupt_key();
  841. return data;
  842. }
  843. #define ABORT_TIMEOUT 5
  844. static void
  845. ftpfs_linear_abort (struct vfs_class *me, struct vfs_s_fh *fh)
  846. {
  847. struct vfs_s_super *super = FH_SUPER;
  848. static unsigned char const ipbuf[3] = { IAC, IP, IAC };
  849. fd_set mask;
  850. char buf[1024];
  851. int dsock = FH_SOCK;
  852. FH_SOCK = -1;
  853. SUP.ctl_connection_busy = 0;
  854. print_vfs_message (_("ftpfs: aborting transfer."));
  855. if (send (SUP.sock, ipbuf, sizeof (ipbuf), MSG_OOB) != sizeof (ipbuf)) {
  856. print_vfs_message (_("ftpfs: abort error: %s"),
  857. unix_error_string (errno));
  858. if (dsock != -1)
  859. close (dsock);
  860. return;
  861. }
  862. if (ftpfs_command (me, super, NONE, "%cABOR", DM) != COMPLETE) {
  863. print_vfs_message (_("ftpfs: abort failed"));
  864. if (dsock != -1)
  865. close (dsock);
  866. return;
  867. }
  868. if (dsock != -1) {
  869. FD_ZERO (&mask);
  870. FD_SET (dsock, &mask);
  871. if (select (dsock + 1, &mask, NULL, NULL, NULL) > 0) {
  872. struct timeval start_tim, tim;
  873. gettimeofday (&start_tim, NULL);
  874. /* flush the remaining data */
  875. while (read (dsock, buf, sizeof (buf)) > 0) {
  876. gettimeofday (&tim, NULL);
  877. if (tim.tv_sec > start_tim.tv_sec + ABORT_TIMEOUT) {
  878. /* server keeps sending, drop the connection and ftpfs_reconnect */
  879. close (dsock);
  880. ftpfs_reconnect (me, super);
  881. return;
  882. }
  883. }
  884. }
  885. close (dsock);
  886. }
  887. if ((ftpfs_get_reply (me, SUP.sock, NULL, 0) == TRANSIENT) && (code == 426))
  888. ftpfs_get_reply (me, SUP.sock, NULL, 0);
  889. }
  890. #if 0
  891. static void
  892. resolve_symlink_without_ls_options(struct vfs_class *me, struct vfs_s_super *super, struct vfs_s_inode *dir)
  893. {
  894. struct linklist *flist;
  895. struct direntry *fe, *fel;
  896. char tmp[MC_MAXPATHLEN];
  897. int depth;
  898. dir->symlink_status = FTPFS_RESOLVING_SYMLINKS;
  899. for (flist = dir->file_list->next; flist != dir->file_list; flist = flist->next) {
  900. /* flist->data->l_stat is alread initialized with 0 */
  901. fel = flist->data;
  902. if (S_ISLNK(fel->s.st_mode) && fel->linkname) {
  903. if (fel->linkname[0] == '/') {
  904. if (strlen (fel->linkname) >= MC_MAXPATHLEN)
  905. continue;
  906. strcpy (tmp, fel->linkname);
  907. } else {
  908. if ((strlen (dir->remote_path) + strlen (fel->linkname)) >= MC_MAXPATHLEN)
  909. continue;
  910. strcpy (tmp, dir->remote_path);
  911. if (tmp[1] != '\0')
  912. strcat (tmp, "/");
  913. strcat (tmp + 1, fel->linkname);
  914. }
  915. for ( depth = 0; depth < 100; depth++) { /* depth protects against recursive symbolic links */
  916. canonicalize_pathname (tmp);
  917. fe = _get_file_entry(bucket, tmp, 0, 0);
  918. if (fe) {
  919. if (S_ISLNK (fe->s.st_mode) && fe->l_stat == 0) {
  920. /* Symlink points to link which isn't resolved, yet. */
  921. if (fe->linkname[0] == '/') {
  922. if (strlen (fe->linkname) >= MC_MAXPATHLEN)
  923. break;
  924. strcpy (tmp, fe->linkname);
  925. } else {
  926. /* at this point tmp looks always like this
  927. /directory/filename, i.e. no need to check
  928. strrchr's return value */
  929. *(strrchr (tmp, '/') + 1) = '\0'; /* dirname */
  930. if ((strlen (tmp) + strlen (fe->linkname)) >= MC_MAXPATHLEN)
  931. break;
  932. strcat (tmp, fe->linkname);
  933. }
  934. continue;
  935. } else {
  936. fel->l_stat = g_new (struct stat, 1);
  937. if ( S_ISLNK (fe->s.st_mode))
  938. *fel->l_stat = *fe->l_stat;
  939. else
  940. *fel->l_stat = fe->s;
  941. (*fel->l_stat).st_ino = bucket->__inode_counter++;
  942. }
  943. }
  944. break;
  945. }
  946. }
  947. }
  948. dir->symlink_status = FTPFS_RESOLVED_SYMLINKS;
  949. }
  950. static void
  951. resolve_symlink_with_ls_options(struct vfs_class *me, struct vfs_s_super *super, struct vfs_s_inode *dir)
  952. {
  953. char buffer[2048] = "", *filename;
  954. int sock;
  955. FILE *fp;
  956. struct stat s;
  957. struct linklist *flist;
  958. struct direntry *fe;
  959. int switch_method = 0;
  960. dir->symlink_status = FTPFS_RESOLVED_SYMLINKS;
  961. if (strchr (dir->remote_path, ' ')) {
  962. if (ftpfs_chdir_internal (bucket, dir->remote_path) != COMPLETE) {
  963. print_vfs_message(_("ftpfs: CWD failed."));
  964. return;
  965. }
  966. sock = ftpfs_open_data_connection (bucket, "LIST -lLa", ".", TYPE_ASCII, 0);
  967. }
  968. else
  969. sock = ftpfs_open_data_connection (bucket, "LIST -lLa",
  970. dir->remote_path, TYPE_ASCII, 0);
  971. if (sock == -1) {
  972. print_vfs_message(_("ftpfs: couldn't resolve symlink"));
  973. return;
  974. }
  975. fp = fdopen(sock, "r");
  976. if (fp == NULL) {
  977. close(sock);
  978. print_vfs_message(_("ftpfs: couldn't resolve symlink"));
  979. return;
  980. }
  981. enable_interrupt_key();
  982. flist = dir->file_list->next;
  983. while (1) {
  984. do {
  985. if (flist == dir->file_list)
  986. goto done;
  987. fe = flist->data;
  988. flist = flist->next;
  989. } while (!S_ISLNK(fe->s.st_mode));
  990. while (1) {
  991. if (fgets (buffer, sizeof (buffer), fp) == NULL)
  992. goto done;
  993. if (MEDATA->logfile){
  994. fputs (buffer, MEDATA->logfile);
  995. fflush (MEDATA->logfile);
  996. }
  997. vfs_die("This code should be commented out\n");
  998. if (vfs_parse_ls_lga (buffer, &s, &filename, NULL)) {
  999. int r = strcmp(fe->name, filename);
  1000. g_free(filename);
  1001. if (r == 0) {
  1002. if (S_ISLNK (s.st_mode)) {
  1003. /* This server doesn't understand LIST -lLa */
  1004. switch_method = 1;
  1005. goto done;
  1006. }
  1007. fe->l_stat = g_new (struct stat, 1);
  1008. if (fe->l_stat == NULL)
  1009. goto done;
  1010. *fe->l_stat = s;
  1011. (*fe->l_stat).st_ino = bucket->__inode_counter++;
  1012. break;
  1013. }
  1014. if (r < 0)
  1015. break;
  1016. }
  1017. }
  1018. }
  1019. done:
  1020. while (fgets(buffer, sizeof(buffer), fp) != NULL);
  1021. disable_interrupt_key();
  1022. fclose(fp);
  1023. ftpfs_get_reply(me, SUP.sock, NULL, 0);
  1024. }
  1025. static void
  1026. resolve_symlink(struct vfs_class *me, struct vfs_s_super *super, struct vfs_s_inode *dir)
  1027. {
  1028. print_vfs_message(_("Resolving symlink..."));
  1029. if (SUP.strict_rfc959_list_cmd)
  1030. resolve_symlink_without_ls_options(me, super, dir);
  1031. else
  1032. resolve_symlink_with_ls_options(me, super, dir);
  1033. }
  1034. #endif
  1035. static int
  1036. ftpfs_dir_load (struct vfs_class *me, struct vfs_s_inode *dir, char *remote_path)
  1037. {
  1038. struct vfs_s_entry *ent;
  1039. struct vfs_s_super *super = dir->super;
  1040. int sock, num_entries = 0;
  1041. char buffer[BUF_8K];
  1042. int cd_first;
  1043. cd_first = ftpfs_first_cd_then_ls || (SUP.strict == RFC_STRICT)
  1044. || (strchr (remote_path, ' ') != NULL);
  1045. again:
  1046. print_vfs_message (_("ftpfs: Reading FTP directory %s... %s%s"),
  1047. remote_path,
  1048. SUP.strict ==
  1049. RFC_STRICT ? _("(strict rfc959)") : "",
  1050. cd_first ? _("(chdir first)") : "");
  1051. if (cd_first) {
  1052. if (ftpfs_chdir_internal (me, super, remote_path) != COMPLETE) {
  1053. ftpfs_errno = ENOENT;
  1054. print_vfs_message (_("ftpfs: CWD failed."));
  1055. return -1;
  1056. }
  1057. }
  1058. gettimeofday (&dir->timestamp, NULL);
  1059. dir->timestamp.tv_sec += ftpfs_directory_timeout;
  1060. if (SUP.strict == RFC_STRICT)
  1061. sock = ftpfs_open_data_connection (me, super, "LIST", 0, TYPE_ASCII, 0);
  1062. else if (cd_first)
  1063. /* Dirty hack to avoid autoprepending / to . */
  1064. /* Wu-ftpd produces strange output for '/' if 'LIST -la .' used */
  1065. sock =
  1066. ftpfs_open_data_connection (me, super, "LIST -la", 0, TYPE_ASCII, 0);
  1067. else {
  1068. /* Trailing "/." is necessary if remote_path is a symlink */
  1069. char *path = concat_dir_and_file (remote_path, ".");
  1070. sock =
  1071. ftpfs_open_data_connection (me, super, "LIST -la", path, TYPE_ASCII,
  1072. 0);
  1073. g_free (path);
  1074. }
  1075. if (sock == -1)
  1076. goto fallback;
  1077. /* Clear the interrupt flag */
  1078. enable_interrupt_key ();
  1079. while (1) {
  1080. int i;
  1081. int res =
  1082. vfs_s_get_line_interruptible (me, buffer, sizeof (buffer),
  1083. sock);
  1084. if (!res)
  1085. break;
  1086. if (res == EINTR) {
  1087. me->verrno = ECONNRESET;
  1088. close (sock);
  1089. disable_interrupt_key ();
  1090. ftpfs_get_reply (me, SUP.sock, NULL, 0);
  1091. print_vfs_message (_("%s: failure"), me->name);
  1092. return -1;
  1093. }
  1094. if (MEDATA->logfile) {
  1095. fputs (buffer, MEDATA->logfile);
  1096. fputs ("\n", MEDATA->logfile);
  1097. fflush (MEDATA->logfile);
  1098. }
  1099. ent = vfs_s_generate_entry (me, NULL, dir, 0);
  1100. i = ent->ino->st.st_nlink;
  1101. if (!vfs_parse_ls_lga
  1102. (buffer, &ent->ino->st, &ent->name, &ent->ino->linkname)) {
  1103. vfs_s_free_entry (me, ent);
  1104. continue;
  1105. }
  1106. ent->ino->st.st_nlink = i; /* Ouch, we need to preserve our counts :-( */
  1107. num_entries++;
  1108. vfs_s_insert_entry (me, dir, ent);
  1109. }
  1110. close (sock);
  1111. me->verrno = E_REMOTE;
  1112. if ((ftpfs_get_reply (me, SUP.sock, NULL, 0) != COMPLETE))
  1113. goto fallback;
  1114. if (num_entries == 0 && cd_first == 0) {
  1115. /* The LIST command may produce an empty output. In such scenario
  1116. it is not clear whether this is caused by `remote_path' being
  1117. a non-existent path or for some other reason (listing emtpy
  1118. directory without the -a option, non-readable directory, etc.).
  1119. Since `dir_load' is a crucial method, when it comes to determine
  1120. whether a given path is a _directory_, the code must try its best
  1121. to determine the type of `remote_path'. The only reliable way to
  1122. achieve this is trough issuing a CWD command. */
  1123. cd_first = 1;
  1124. goto again;
  1125. }
  1126. if (SUP.strict == RFC_AUTODETECT)
  1127. SUP.strict = RFC_DARING;
  1128. print_vfs_message (_("%s: done."), me->name);
  1129. return 0;
  1130. fallback:
  1131. if (SUP.strict == RFC_AUTODETECT) {
  1132. /* It's our first attempt to get a directory listing from this
  1133. server (UNIX style LIST command) */
  1134. SUP.strict = RFC_STRICT;
  1135. /* I hate goto, but recursive call needs another 8K on stack */
  1136. /* return ftpfs_dir_load (me, dir, remote_path); */
  1137. cd_first = 1;
  1138. goto again;
  1139. }
  1140. print_vfs_message (_("ftpfs: failed; nowhere to fallback to"));
  1141. ERRNOR (EACCES, -1);
  1142. }
  1143. static int
  1144. ftpfs_file_store (struct vfs_class *me, struct vfs_s_fh *fh, char *name,
  1145. char *localname)
  1146. {
  1147. int h, sock, n_read, n_written;
  1148. off_t n_stored;
  1149. #ifdef HAVE_STRUCT_LINGER_L_LINGER
  1150. struct linger li;
  1151. #else
  1152. int flag_one = 1;
  1153. #endif
  1154. char buffer[8192];
  1155. struct stat s;
  1156. char *w_buf;
  1157. struct vfs_s_super *super = FH_SUPER;
  1158. h = open (localname, O_RDONLY);
  1159. if (h == -1)
  1160. ERRNOR (EIO, -1);
  1161. sock =
  1162. ftpfs_open_data_connection (me, super,
  1163. fh->u.ftp.append ? "APPE" : "STOR", name,
  1164. TYPE_BINARY, 0);
  1165. if (sock < 0 || fstat (h, &s) == -1) {
  1166. close (h);
  1167. return -1;
  1168. }
  1169. #ifdef HAVE_STRUCT_LINGER_L_LINGER
  1170. li.l_onoff = 1;
  1171. li.l_linger = 120;
  1172. setsockopt (sock, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof (li));
  1173. #else
  1174. setsockopt (sock, SOL_SOCKET, SO_LINGER, &flag_one, sizeof (flag_one));
  1175. #endif
  1176. n_stored = 0;
  1177. enable_interrupt_key ();
  1178. while (1) {
  1179. while ((n_read = read (h, buffer, sizeof (buffer))) == -1) {
  1180. if (errno == EINTR) {
  1181. if (got_interrupt ()) {
  1182. ftpfs_errno = EINTR;
  1183. goto error_return;
  1184. } else
  1185. continue;
  1186. }
  1187. ftpfs_errno = errno;
  1188. goto error_return;
  1189. }
  1190. if (n_read == 0)
  1191. break;
  1192. n_stored += n_read;
  1193. w_buf = buffer;
  1194. while ((n_written = write (sock, w_buf, n_read)) != n_read) {
  1195. if (n_written == -1) {
  1196. if (errno == EINTR && !got_interrupt ()) {
  1197. continue;
  1198. }
  1199. ftpfs_errno = errno;
  1200. goto error_return;
  1201. }
  1202. w_buf += n_written;
  1203. n_read -= n_written;
  1204. }
  1205. print_vfs_message (_("ftpfs: storing file %lu (%lu)"),
  1206. (unsigned long) n_stored, (unsigned long) s.st_size);
  1207. }
  1208. disable_interrupt_key ();
  1209. close (sock);
  1210. close (h);
  1211. if (ftpfs_get_reply (me, SUP.sock, NULL, 0) != COMPLETE)
  1212. ERRNOR (EIO, -1);
  1213. return 0;
  1214. error_return:
  1215. disable_interrupt_key ();
  1216. close (sock);
  1217. close (h);
  1218. ftpfs_get_reply (me, SUP.sock, NULL, 0);
  1219. return -1;
  1220. }
  1221. static int
  1222. ftpfs_linear_start (struct vfs_class *me, struct vfs_s_fh *fh, off_t offset)
  1223. {
  1224. char *name = vfs_s_fullpath (me, fh->ino);
  1225. if (!name)
  1226. return 0;
  1227. FH_SOCK = ftpfs_open_data_connection(me, FH_SUPER, "RETR", name, TYPE_BINARY, offset);
  1228. g_free (name);
  1229. if (FH_SOCK == -1)
  1230. ERRNOR (EACCES, 0);
  1231. fh->linear = LS_LINEAR_OPEN;
  1232. FH_SUPER->u.ftp.ctl_connection_busy = 1;
  1233. fh->u.ftp.append = 0;
  1234. return 1;
  1235. }
  1236. static int
  1237. ftpfs_linear_read (struct vfs_class *me, struct vfs_s_fh *fh, void *buf, int len)
  1238. {
  1239. int n;
  1240. struct vfs_s_super *super = FH_SUPER;
  1241. while ((n = read (FH_SOCK, buf, len))<0) {
  1242. if ((errno == EINTR) && !got_interrupt())
  1243. continue;
  1244. break;
  1245. }
  1246. if (n<0)
  1247. ftpfs_linear_abort(me, fh);
  1248. if (!n) {
  1249. SUP.ctl_connection_busy = 0;
  1250. close (FH_SOCK);
  1251. FH_SOCK = -1;
  1252. if ((ftpfs_get_reply (me, SUP.sock, NULL, 0) != COMPLETE))
  1253. ERRNOR (E_REMOTE, -1);
  1254. return 0;
  1255. }
  1256. ERRNOR (errno, n);
  1257. }
  1258. static void
  1259. ftpfs_linear_close (struct vfs_class *me, struct vfs_s_fh *fh)
  1260. {
  1261. if (FH_SOCK != -1)
  1262. ftpfs_linear_abort(me, fh);
  1263. }
  1264. static int ftpfs_ctl (void *fh, int ctlop, void *arg)
  1265. {
  1266. (void) arg;
  1267. switch (ctlop) {
  1268. case VFS_CTL_IS_NOTREADY:
  1269. {
  1270. int v;
  1271. if (!FH->linear)
  1272. vfs_die ("You may not do this");
  1273. if (FH->linear == LS_LINEAR_CLOSED || FH->linear == LS_LINEAR_PREOPEN)
  1274. return 0;
  1275. v = vfs_s_select_on_two (FH->u.ftp.sock, 0);
  1276. if (((v < 0) && (errno == EINTR)) || v == 0)
  1277. return 1;
  1278. return 0;
  1279. }
  1280. default:
  1281. return 0;
  1282. }
  1283. }
  1284. static int
  1285. ftpfs_send_command(struct vfs_class *me, const char *filename, const char *cmd, int flags)
  1286. {
  1287. const char *rpath;
  1288. char *p, *mpath = g_strdup(filename);
  1289. struct vfs_s_super *super;
  1290. int r;
  1291. int flush_directory_cache = (flags & OPT_FLUSH);
  1292. if (!(rpath = vfs_s_get_path_mangle(me, mpath, &super, 0))) {
  1293. g_free(mpath);
  1294. return -1;
  1295. }
  1296. p = ftpfs_translate_path (me, super, rpath);
  1297. r = ftpfs_command (me, super, WAIT_REPLY, cmd, p);
  1298. g_free (p);
  1299. vfs_stamp_create (&vfs_ftpfs_ops, super);
  1300. if (flags & OPT_IGNORE_ERROR)
  1301. r = COMPLETE;
  1302. if (r != COMPLETE) {
  1303. me->verrno = EPERM;
  1304. g_free (mpath);
  1305. return -1;
  1306. }
  1307. if (flush_directory_cache)
  1308. vfs_s_invalidate(me, super);
  1309. g_free(mpath);
  1310. return 0;
  1311. }
  1312. /* This routine is called as the last step in load_setup */
  1313. void
  1314. ftpfs_init_passwd(void)
  1315. {
  1316. ftpfs_anonymous_passwd = load_anon_passwd ();
  1317. if (ftpfs_anonymous_passwd)
  1318. return;
  1319. /* If there is no anonymous ftp password specified
  1320. * then we'll just use anonymous@
  1321. * We don't send any other thing because:
  1322. * - We want to remain anonymous
  1323. * - We want to stop SPAM
  1324. * - We don't want to let ftp sites to discriminate by the user,
  1325. * host or country.
  1326. */
  1327. ftpfs_anonymous_passwd = g_strdup ("anonymous@");
  1328. }
  1329. static int ftpfs_chmod (struct vfs_class *me, const char *path, int mode)
  1330. {
  1331. char buf[BUF_SMALL];
  1332. g_snprintf(buf, sizeof(buf), "SITE CHMOD %4.4o /%%s", mode & 07777);
  1333. return ftpfs_send_command(me, path, buf, OPT_FLUSH);
  1334. }
  1335. static int ftpfs_chown (struct vfs_class *me, const char *path, int owner, int group)
  1336. {
  1337. #if 0
  1338. ftpfs_errno = EPERM;
  1339. return -1;
  1340. #else
  1341. /* Everyone knows it is not possible to chown remotely, so why bother them.
  1342. If someone's root, then copy/move will always try to chown it... */
  1343. (void) me;
  1344. (void) path;
  1345. (void) owner;
  1346. (void) group;
  1347. return 0;
  1348. #endif
  1349. }
  1350. static int ftpfs_unlink (struct vfs_class *me, const char *path)
  1351. {
  1352. return ftpfs_send_command(me, path, "DELE /%s", OPT_FLUSH);
  1353. }
  1354. /* Return 1 if path is the same directory as the one we are in now */
  1355. static int
  1356. ftpfs_is_same_dir (struct vfs_class *me, struct vfs_s_super *super, const char *path)
  1357. {
  1358. (void) me;
  1359. if (!SUP.cwdir)
  1360. return 0;
  1361. if (strcmp (path, SUP.cwdir) == 0)
  1362. return 1;
  1363. return 0;
  1364. }
  1365. static int
  1366. ftpfs_chdir_internal (struct vfs_class *me, struct vfs_s_super *super, const char *remote_path)
  1367. {
  1368. int r;
  1369. char *p;
  1370. if (!SUP.cwd_deferred && ftpfs_is_same_dir (me, super, remote_path))
  1371. return COMPLETE;
  1372. p = ftpfs_translate_path (me, super, remote_path);
  1373. r = ftpfs_command (me, super, WAIT_REPLY, "CWD /%s", p);
  1374. g_free (p);
  1375. if (r != COMPLETE) {
  1376. ftpfs_errno = EIO;
  1377. } else {
  1378. g_free(SUP.cwdir);
  1379. SUP.cwdir = g_strdup (remote_path);
  1380. SUP.cwd_deferred = 0;
  1381. }
  1382. return r;
  1383. }
  1384. static int ftpfs_rename (struct vfs_class *me, const char *path1, const char *path2)
  1385. {
  1386. ftpfs_send_command(me, path1, "RNFR /%s", OPT_FLUSH);
  1387. return ftpfs_send_command(me, path2, "RNTO /%s", OPT_FLUSH);
  1388. }
  1389. static int ftpfs_mkdir (struct vfs_class *me, const char *path, mode_t mode)
  1390. {
  1391. (void) mode; /* FIXME: should be used */
  1392. return ftpfs_send_command(me, path, "MKD /%s", OPT_FLUSH);
  1393. }
  1394. static int ftpfs_rmdir (struct vfs_class *me, const char *path)
  1395. {
  1396. return ftpfs_send_command(me, path, "RMD /%s", OPT_FLUSH);
  1397. }
  1398. static int
  1399. ftpfs_fh_open (struct vfs_class *me, struct vfs_s_fh *fh, int flags,
  1400. int mode)
  1401. {
  1402. (void) mode;
  1403. fh->u.ftp.append = 0;
  1404. /* File will be written only, so no need to retrieve it from ftp server */
  1405. if (((flags & O_WRONLY) == O_WRONLY) && !(flags & (O_RDONLY | O_RDWR))) {
  1406. #ifdef HAVE_STRUCT_LINGER_L_LINGER
  1407. struct linger li;
  1408. #else
  1409. int li = 1;
  1410. #endif
  1411. char *name;
  1412. /* ftpfs_linear_start() called, so data will be written
  1413. * to local temporary file and stored to ftp server
  1414. * by vfs_s_close later
  1415. */
  1416. if (FH_SUPER->u.ftp.ctl_connection_busy) {
  1417. if (!fh->ino->localname) {
  1418. int handle = vfs_mkstemps (&fh->ino->localname, me->name,
  1419. fh->ino->ent->name);
  1420. if (handle == -1)
  1421. return -1;
  1422. close (handle);
  1423. fh->u.ftp.append = flags & O_APPEND;
  1424. }
  1425. return 0;
  1426. }
  1427. name = vfs_s_fullpath (me, fh->ino);
  1428. if (!name)
  1429. return -1;
  1430. fh->handle =
  1431. ftpfs_open_data_connection (me, fh->ino->super,
  1432. (flags & O_APPEND) ? "APPE" :
  1433. "STOR", name, TYPE_BINARY, 0);
  1434. g_free (name);
  1435. if (fh->handle < 0)
  1436. return -1;
  1437. #ifdef HAVE_STRUCT_LINGER_L_LINGER
  1438. li.l_onoff = 1;
  1439. li.l_linger = 120;
  1440. #endif
  1441. setsockopt (fh->handle, SOL_SOCKET, SO_LINGER, &li, sizeof (li));
  1442. if (fh->ino->localname) {
  1443. unlink (fh->ino->localname);
  1444. g_free (fh->ino->localname);
  1445. fh->ino->localname = NULL;
  1446. }
  1447. return 0;
  1448. }
  1449. if (!fh->ino->localname)
  1450. if (vfs_s_retrieve_file (me, fh->ino) == -1)
  1451. return -1;
  1452. if (!fh->ino->localname)
  1453. vfs_die ("retrieve_file failed to fill in localname");
  1454. return 0;
  1455. }
  1456. static int ftpfs_fh_close (struct vfs_class *me, struct vfs_s_fh *fh)
  1457. {
  1458. if (fh->handle != -1 && !fh->ino->localname){
  1459. close (fh->handle);
  1460. fh->handle = -1;
  1461. /* File is stored to destination already, so
  1462. * we prevent MEDATA->ftpfs_file_store() call from vfs_s_close ()
  1463. */
  1464. fh->changed = 0;
  1465. if (ftpfs_get_reply (me, fh->ino->SUP.sock, NULL, 0) != COMPLETE)
  1466. ERRNOR (EIO, -1);
  1467. vfs_s_invalidate (me, FH_SUPER);
  1468. }
  1469. return 0;
  1470. }
  1471. static void
  1472. ftpfs_done (struct vfs_class *me)
  1473. {
  1474. struct no_proxy_entry *np;
  1475. (void) me;
  1476. while (no_proxy) {
  1477. np = no_proxy->next;
  1478. g_free (no_proxy->domain);
  1479. g_free (no_proxy);
  1480. no_proxy = np;
  1481. }
  1482. g_free (ftpfs_anonymous_passwd);
  1483. g_free (ftpfs_proxy_host);
  1484. }
  1485. static void
  1486. ftpfs_fill_names (struct vfs_class *me, fill_names_f func)
  1487. {
  1488. struct vfs_s_super *super = MEDATA->supers;
  1489. char *name;
  1490. while (super){
  1491. name = g_strconcat ("/#ftp:", SUP.user, "@", SUP.host, "/", SUP.cwdir, (char *) NULL);
  1492. (*func)(name);
  1493. g_free (name);
  1494. super = super->next;
  1495. }
  1496. }
  1497. static char buffer[BUF_MEDIUM];
  1498. static char *netrc;
  1499. static const char *netrcp;
  1500. /* This should match the keywords[] array below */
  1501. typedef enum {
  1502. NETRC_NONE = 0,
  1503. NETRC_DEFAULT,
  1504. NETRC_MACHINE,
  1505. NETRC_LOGIN,
  1506. NETRC_PASSWORD,
  1507. NETRC_PASSWD,
  1508. NETRC_ACCOUNT,
  1509. NETRC_MACDEF,
  1510. NETRC_UNKNOWN
  1511. } keyword_t;
  1512. static keyword_t ftpfs_netrc_next (void)
  1513. {
  1514. char *p;
  1515. keyword_t i;
  1516. static const char *const keywords[] = { "default", "machine",
  1517. "login", "password", "passwd", "account", "macdef", NULL
  1518. };
  1519. while (1) {
  1520. netrcp = skip_separators (netrcp);
  1521. if (*netrcp != '\n')
  1522. break;
  1523. netrcp++;
  1524. }
  1525. if (!*netrcp)
  1526. return NETRC_NONE;
  1527. p = buffer;
  1528. if (*netrcp == '"') {
  1529. for (netrcp++; *netrcp != '"' && *netrcp; netrcp++) {
  1530. if (*netrcp == '\\')
  1531. netrcp++;
  1532. *p++ = *netrcp;
  1533. }
  1534. } else {
  1535. for (; *netrcp != '\n' && *netrcp != '\t' && *netrcp != ' ' &&
  1536. *netrcp != ',' && *netrcp; netrcp++) {
  1537. if (*netrcp == '\\')
  1538. netrcp++;
  1539. *p++ = *netrcp;
  1540. }
  1541. }
  1542. *p = 0;
  1543. if (!*buffer)
  1544. return NETRC_NONE;
  1545. i = NETRC_DEFAULT;
  1546. while (keywords[i - 1]) {
  1547. if (!strcmp (keywords[i - 1], buffer))
  1548. return i;
  1549. i++;
  1550. }
  1551. return NETRC_UNKNOWN;
  1552. }
  1553. static int ftpfs_netrc_bad_mode (const char *netrcname)
  1554. {
  1555. static int be_angry = 1;
  1556. struct stat mystat;
  1557. if (stat (netrcname, &mystat) >= 0 && (mystat.st_mode & 077)) {
  1558. if (be_angry) {
  1559. message (1, MSG_ERROR,
  1560. _("~/.netrc file has incorrect mode.\n"
  1561. "Remove password or correct mode."));
  1562. be_angry = 0;
  1563. }
  1564. return 1;
  1565. }
  1566. return 0;
  1567. }
  1568. /* Scan .netrc until we find matching "machine" or "default"
  1569. * domain is used for additional matching
  1570. * No search is done after "default" in compliance with "man netrc"
  1571. * Return 0 if found, -1 otherwise */
  1572. static int ftpfs_find_machine (const char *host, const char *domain)
  1573. {
  1574. keyword_t keyword;
  1575. while ((keyword = ftpfs_netrc_next ()) != NETRC_NONE) {
  1576. if (keyword == NETRC_DEFAULT)
  1577. return 0;
  1578. if (keyword == NETRC_MACDEF) {
  1579. /* Scan for an empty line, which concludes "macdef" */
  1580. do {
  1581. while (*netrcp && *netrcp != '\n')
  1582. netrcp++;
  1583. if (*netrcp != '\n')
  1584. break;
  1585. netrcp++;
  1586. } while (*netrcp && *netrcp != '\n');
  1587. continue;
  1588. }
  1589. if (keyword != NETRC_MACHINE)
  1590. continue;
  1591. /* Take machine name */
  1592. if (ftpfs_netrc_next () == NETRC_NONE)
  1593. break;
  1594. if (g_strcasecmp (host, buffer)) {
  1595. /* Try adding our domain to short names in .netrc */
  1596. const char *host_domain = strchr (host, '.');
  1597. if (!host_domain)
  1598. continue;
  1599. /* Compare domain part */
  1600. if (g_strcasecmp (host_domain, domain))
  1601. continue;
  1602. /* Compare local part */
  1603. if (g_strncasecmp (host, buffer, host_domain - host))
  1604. continue;
  1605. }
  1606. return 0;
  1607. }
  1608. /* end of .netrc */
  1609. return -1;
  1610. }
  1611. /* Extract login and password from .netrc for the host.
  1612. * pass may be NULL.
  1613. * Returns 0 for success, -1 for error */
  1614. static int ftpfs_netrc_lookup (const char *host, char **login, char **pass)
  1615. {
  1616. char *netrcname;
  1617. char *tmp_pass = NULL;
  1618. char hostname[MAXHOSTNAMELEN];
  1619. const char *domain;
  1620. keyword_t keyword;
  1621. static struct rupcache {
  1622. struct rupcache *next;
  1623. char *host;
  1624. char *login;
  1625. char *pass;
  1626. } *rup_cache = NULL, *rupp;
  1627. /* Initialize *login and *pass */
  1628. if (!login)
  1629. return 0;
  1630. *login = NULL;
  1631. if (pass)
  1632. *pass = NULL;
  1633. /* Look up in the cache first */
  1634. for (rupp = rup_cache; rupp != NULL; rupp = rupp->next) {
  1635. if (!strcmp (host, rupp->host)) {
  1636. if (rupp->login)
  1637. *login = g_strdup (rupp->login);
  1638. if (pass && rupp->pass)
  1639. *pass = g_strdup (rupp->pass);
  1640. return 0;
  1641. }
  1642. }
  1643. /* Load current .netrc */
  1644. netrcname = concat_dir_and_file (home_dir, ".netrc");
  1645. netrcp = netrc = load_file (netrcname);
  1646. if (netrc == NULL) {
  1647. g_free (netrcname);
  1648. return 0;
  1649. }
  1650. /* Find our own domain name */
  1651. if (gethostname (hostname, sizeof (hostname)) < 0)
  1652. *hostname = 0;
  1653. if (!(domain = strchr (hostname, '.')))
  1654. domain = "";
  1655. /* Scan for "default" and matching "machine" keywords */
  1656. ftpfs_find_machine (host, domain);
  1657. /* Scan for keywords following "default" and "machine" */
  1658. while (1) {
  1659. int need_break = 0;
  1660. keyword = ftpfs_netrc_next ();
  1661. switch (keyword) {
  1662. case NETRC_LOGIN:
  1663. if (ftpfs_netrc_next () == NETRC_NONE) {
  1664. need_break = 1;
  1665. break;
  1666. }
  1667. /* We have another name already - should not happen */
  1668. if (*login) {
  1669. need_break = 1;
  1670. break;
  1671. }
  1672. /* We have login name now */
  1673. *login = g_strdup (buffer);
  1674. break;
  1675. case NETRC_PASSWORD:
  1676. case NETRC_PASSWD:
  1677. if (ftpfs_netrc_next () == NETRC_NONE) {
  1678. need_break = 1;
  1679. break;
  1680. }
  1681. /* Ignore unsafe passwords */
  1682. if (strcmp (*login, "anonymous") && strcmp (*login, "ftp")
  1683. && ftpfs_netrc_bad_mode (netrcname)) {
  1684. need_break = 1;
  1685. break;
  1686. }
  1687. /* Remember password. pass may be NULL, so use tmp_pass */
  1688. if (tmp_pass == NULL)
  1689. tmp_pass = g_strdup (buffer);
  1690. break;
  1691. case NETRC_ACCOUNT:
  1692. /* "account" is followed by a token which we ignore */
  1693. if (ftpfs_netrc_next () == NETRC_NONE) {
  1694. need_break = 1;
  1695. break;
  1696. }
  1697. /* Ignore account, but warn user anyways */
  1698. ftpfs_netrc_bad_mode (netrcname);
  1699. break;
  1700. default:
  1701. /* Unexpected keyword or end of file */
  1702. need_break = 1;
  1703. break;
  1704. }
  1705. if (need_break)
  1706. break;
  1707. }
  1708. g_free (netrc);
  1709. g_free (netrcname);
  1710. rupp = g_new (struct rupcache, 1);
  1711. rupp->host = g_strdup (host);
  1712. rupp->login = rupp->pass = 0;
  1713. if (*login != NULL) {
  1714. rupp->login = g_strdup (*login);
  1715. }
  1716. if (tmp_pass != NULL)
  1717. rupp->pass = g_strdup (tmp_pass);
  1718. rupp->next = rup_cache;
  1719. rup_cache = rupp;
  1720. if (pass)
  1721. *pass = tmp_pass;
  1722. return 0;
  1723. }
  1724. void
  1725. init_ftpfs (void)
  1726. {
  1727. static struct vfs_s_subclass ftpfs_subclass;
  1728. ftpfs_subclass.flags = VFS_S_REMOTE;
  1729. ftpfs_subclass.archive_same = ftpfs_archive_same;
  1730. ftpfs_subclass.open_archive = ftpfs_open_archive;
  1731. ftpfs_subclass.free_archive = ftpfs_free_archive;
  1732. ftpfs_subclass.fh_open = ftpfs_fh_open;
  1733. ftpfs_subclass.fh_close = ftpfs_fh_close;
  1734. ftpfs_subclass.dir_load = ftpfs_dir_load;
  1735. ftpfs_subclass.file_store = ftpfs_file_store;
  1736. ftpfs_subclass.linear_start = ftpfs_linear_start;
  1737. ftpfs_subclass.linear_read = ftpfs_linear_read;
  1738. ftpfs_subclass.linear_close = ftpfs_linear_close;
  1739. vfs_s_init_class (&vfs_ftpfs_ops, &ftpfs_subclass);
  1740. vfs_ftpfs_ops.name = "ftpfs";
  1741. vfs_ftpfs_ops.flags = VFSF_NOLINKS;
  1742. vfs_ftpfs_ops.prefix = "ftp:";
  1743. vfs_ftpfs_ops.done = &ftpfs_done;
  1744. vfs_ftpfs_ops.fill_names = ftpfs_fill_names;
  1745. vfs_ftpfs_ops.chmod = ftpfs_chmod;
  1746. vfs_ftpfs_ops.chown = ftpfs_chown;
  1747. vfs_ftpfs_ops.unlink = ftpfs_unlink;
  1748. vfs_ftpfs_ops.rename = ftpfs_rename;
  1749. vfs_ftpfs_ops.mkdir = ftpfs_mkdir;
  1750. vfs_ftpfs_ops.rmdir = ftpfs_rmdir;
  1751. vfs_ftpfs_ops.ctl = ftpfs_ctl;
  1752. vfs_register_class (&vfs_ftpfs_ops);
  1753. }