Mercurial > gftp.yaz
annotate lib/protocols.c @ 485:7334a74db6f6
2004-6-15 Brian Masney <masneyb@gftp.org>
* lib/protocols.c - added supported for multiline VMS directory
listings. Also, parse the date correctly for single line VMS
directory listings
* lib/gftp.h lib/local.c lib/rfc2068.c lib/rfc959.c lib/sshv.c -
added function pointer get_next_dirlist_line to gftp_request structure.
This will retrieve the next line of input for the directory listing.
This is only implemented in the FTP protocol at the moment. It shouldn't
be needed in the other protocols
author | masneyb |
---|---|
date | Wed, 16 Jun 2004 02:57:02 +0000 |
parents | 18c6d173f5f2 |
children | 76c4e4cd108e |
rev | line source |
---|---|
1 | 1 /*****************************************************************************/ |
2 /* protocols.c - Skeleton functions for the protocols gftp supports */ | |
122 | 3 /* Copyright (C) 1998-2003 Brian Masney <masneyb@gftp.org> */ |
1 | 4 /* */ |
5 /* This program is free software; you can redistribute it and/or modify */ | |
6 /* it under the terms of the GNU General Public License as published by */ | |
7 /* the Free Software Foundation; either version 2 of the License, or */ | |
8 /* (at your option) any later version. */ | |
9 /* */ | |
10 /* This program is distributed in the hope that it will be useful, */ | |
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ | |
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ | |
13 /* GNU General Public License for more details. */ | |
14 /* */ | |
15 /* You should have received a copy of the GNU General Public License */ | |
16 /* along with this program; if not, write to the Free Software */ | |
17 /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA */ | |
18 /*****************************************************************************/ | |
19 | |
20 #include "gftp.h" | |
33 | 21 static const char cvsid[] = "$Id$"; |
1 | 22 |
23 gftp_request * | |
24 gftp_request_new (void) | |
25 { | |
26 gftp_request *request; | |
27 | |
28 request = g_malloc0 (sizeof (*request)); | |
66 | 29 request->datafd = -1; |
30 request->cachefd = -1; | |
122 | 31 request->server_type = GFTP_DIRTYPE_OTHER; |
1 | 32 return (request); |
33 } | |
136 | 34 |
1 | 35 |
36 void | |
67 | 37 gftp_request_destroy (gftp_request * request, int free_request) |
1 | 38 { |
39 g_return_if_fail (request != NULL); | |
40 | |
41 gftp_disconnect (request); | |
42 | |
43 if (request->destroy != NULL) | |
44 request->destroy (request); | |
45 | |
46 if (request->hostname) | |
47 g_free (request->hostname); | |
48 if (request->username) | |
49 g_free (request->username); | |
50 if (request->password) | |
51 { | |
52 memset (request->password, 0, strlen (request->password)); | |
53 g_free (request->password); | |
54 } | |
55 if (request->account) | |
56 { | |
57 memset (request->account, 0, strlen (request->account)); | |
58 g_free (request->account); | |
59 } | |
60 if (request->directory) | |
61 g_free (request->directory); | |
62 if (request->last_ftp_response) | |
63 g_free (request->last_ftp_response); | |
64 if (request->protocol_data) | |
65 g_free (request->protocol_data); | |
67 | 66 |
198 | 67 if (request->local_options_vars != NULL) |
68 { | |
201 | 69 gftp_config_free_options (request->local_options_vars, |
70 request->local_options_hash, | |
71 request->num_local_options_vars); | |
198 | 72 } |
73 | |
1 | 74 memset (request, 0, sizeof (*request)); |
67 | 75 |
76 if (free_request) | |
77 g_free (request); | |
78 else | |
79 { | |
80 request->datafd = -1; | |
81 request->cachefd = -1; | |
82 } | |
1 | 83 } |
84 | |
85 | |
309 | 86 /* This function is called to copy protocol specific data from one request |
87 structure to another. This is typically called when a file transfer is | |
88 completed, state information can be copied back to the main window */ | |
89 void | |
90 gftp_copy_param_options (gftp_request * dest_request, | |
91 gftp_request * src_request) | |
92 { | |
93 g_return_if_fail (dest_request != NULL); | |
94 g_return_if_fail (src_request != NULL); | |
95 g_return_if_fail (dest_request->protonum == src_request->protonum); | |
96 | |
97 if (dest_request->copy_param_options) | |
98 dest_request->copy_param_options (dest_request, src_request); | |
99 } | |
100 | |
101 | |
1 | 102 void |
103 gftp_file_destroy (gftp_file * file) | |
104 { | |
105 g_return_if_fail (file != NULL); | |
106 | |
107 if (file->file) | |
108 g_free (file->file); | |
349 | 109 if (file->utf8_file) |
110 g_free (file->utf8_file); | |
1 | 111 if (file->user) |
112 g_free (file->user); | |
113 if (file->group) | |
114 g_free (file->group); | |
115 if (file->attribs) | |
116 g_free (file->attribs); | |
117 if (file->destfile) | |
118 g_free (file->destfile); | |
119 memset (file, 0, sizeof (*file)); | |
120 } | |
121 | |
122 | |
123 int | |
124 gftp_connect (gftp_request * request) | |
125 { | |
177 | 126 int ret; |
127 | |
84 | 128 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1 | 129 |
130 if (request->connect == NULL) | |
84 | 131 return (GFTP_EFATAL); |
1 | 132 |
177 | 133 if ((ret = gftp_set_config_options (request)) < 0) |
134 return (ret); | |
1 | 135 |
136 return (request->connect (request)); | |
137 } | |
138 | |
139 | |
140 void | |
141 gftp_disconnect (gftp_request * request) | |
142 { | |
143 g_return_if_fail (request != NULL); | |
144 | |
145 #if defined (HAVE_GETADDRINFO) && defined (HAVE_GAI_STRERROR) | |
151 | 146 if (request->free_hostp && request->hostp != NULL) |
1 | 147 freeaddrinfo (request->hostp); |
148 #endif | |
149 request->hostp = NULL; | |
150 | |
168 | 151 #ifdef USE_SSL |
152 if (request->ssl != NULL) | |
153 { | |
154 SSL_free (request->ssl); | |
155 request->ssl = NULL; | |
156 } | |
157 #endif | |
158 | |
187 | 159 #if GLIB_MAJOR_VERSION > 1 |
160 if (request->iconv_initialized) | |
161 { | |
162 g_iconv_close (request->iconv); | |
163 request->iconv_initialized = 0; | |
164 } | |
165 #endif | |
166 | |
1 | 167 request->cached = 0; |
168 if (request->disconnect == NULL) | |
169 return; | |
170 request->disconnect (request); | |
171 } | |
172 | |
173 | |
58 | 174 off_t |
175 gftp_get_file (gftp_request * request, const char *filename, int fd, | |
244 | 176 off_t startsize) |
1 | 177 { |
84 | 178 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1 | 179 |
180 request->cached = 0; | |
181 if (request->get_file == NULL) | |
84 | 182 return (GFTP_EFATAL); |
244 | 183 |
1 | 184 return (request->get_file (request, filename, fd, startsize)); |
185 } | |
186 | |
187 | |
188 int | |
58 | 189 gftp_put_file (gftp_request * request, const char *filename, int fd, |
244 | 190 off_t startsize, off_t totalsize) |
1 | 191 { |
84 | 192 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1 | 193 |
194 request->cached = 0; | |
195 if (request->put_file == NULL) | |
84 | 196 return (GFTP_EFATAL); |
1 | 197 return (request->put_file (request, filename, fd, startsize, totalsize)); |
198 } | |
199 | |
200 | |
261 | 201 off_t |
1 | 202 gftp_transfer_file (gftp_request * fromreq, const char *fromfile, |
244 | 203 int fromfd, off_t fromsize, |
1 | 204 gftp_request * toreq, const char *tofile, |
244 | 205 int tofd, off_t tosize) |
1 | 206 { |
469 | 207 /* Needed for systems that size(float) < size(void *) */ |
208 union { intptr_t i; float f; } maxkbs; | |
261 | 209 off_t size; |
84 | 210 int ret; |
1 | 211 |
84 | 212 g_return_val_if_fail (fromreq != NULL, GFTP_EFATAL); |
213 g_return_val_if_fail (fromfile != NULL, GFTP_EFATAL); | |
214 g_return_val_if_fail (toreq != NULL, GFTP_EFATAL); | |
215 g_return_val_if_fail (tofile != NULL, GFTP_EFATAL); | |
216 | |
469 | 217 gftp_lookup_request_option (toreq, "maxkbs", &maxkbs.f); |
218 | |
219 if (maxkbs.f > 0) | |
294 | 220 { |
221 toreq->logging_function (gftp_logging_misc, toreq, | |
222 _("File transfer will be throttled to %.2f KB/s\n"), | |
469 | 223 maxkbs.f); |
294 | 224 } |
225 | |
87 | 226 if (fromreq->protonum == toreq->protonum && |
84 | 227 fromreq->transfer_file != NULL) |
228 return (fromreq->transfer_file (fromreq, fromfile, fromsize, toreq, | |
229 tofile, tosize)); | |
1 | 230 |
231 fromreq->cached = 0; | |
232 toreq->cached = 0; | |
443 | 233 |
234 get_file: | |
235 size = gftp_get_file (fromreq, fromfile, fromfd, tosize); | |
236 if (size < 0) | |
1 | 237 { |
443 | 238 if (size == GFTP_ETIMEDOUT) |
239 { | |
240 ret = gftp_connect (fromreq); | |
241 if (ret < 0) | |
242 return (ret); | |
243 | |
244 goto get_file; | |
245 } | |
246 | |
247 return (size); | |
248 } | |
249 | |
250 put_file: | |
251 ret = gftp_put_file (toreq, tofile, tofd, tosize, size); | |
252 if (ret != 0) | |
253 { | |
254 if (size == GFTP_ETIMEDOUT) | |
255 { | |
256 ret = gftp_connect (fromreq); | |
257 if (ret < 0) | |
258 return (ret); | |
259 | |
260 goto put_file; | |
261 } | |
262 | |
40 | 263 if (gftp_abort_transfer (fromreq) != 0) |
264 gftp_end_transfer (fromreq); | |
265 | |
84 | 266 return (ret); |
1 | 267 } |
268 | |
269 return (size); | |
270 } | |
271 | |
272 | |
58 | 273 ssize_t |
1 | 274 gftp_get_next_file_chunk (gftp_request * request, char *buf, size_t size) |
275 { | |
84 | 276 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
277 g_return_val_if_fail (buf != NULL, GFTP_EFATAL); | |
1 | 278 |
279 if (request->get_next_file_chunk != NULL) | |
280 return (request->get_next_file_chunk (request, buf, size)); | |
281 | |
168 | 282 return (request->read_function (request, buf, size, request->datafd)); |
1 | 283 } |
284 | |
285 | |
58 | 286 ssize_t |
1 | 287 gftp_put_next_file_chunk (gftp_request * request, char *buf, size_t size) |
288 { | |
84 | 289 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
290 g_return_val_if_fail (buf != NULL, GFTP_EFATAL); | |
1 | 291 |
292 if (request->put_next_file_chunk != NULL) | |
293 return (request->put_next_file_chunk (request, buf, size)); | |
294 | |
295 if (size == 0) | |
296 return (0); | |
297 | |
168 | 298 return (request->write_function (request, buf, size, request->datafd)); |
1 | 299 } |
300 | |
301 | |
302 int | |
303 gftp_end_transfer (gftp_request * request) | |
304 { | |
305 int ret; | |
306 | |
84 | 307 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1 | 308 |
40 | 309 if (!request->cached && |
310 request->end_transfer != NULL) | |
311 ret = request->end_transfer (request); | |
312 else | |
313 ret = 0; | |
1 | 314 |
58 | 315 if (request->cachefd > 0) |
1 | 316 { |
58 | 317 close (request->cachefd); |
318 request->cachefd = -1; | |
1 | 319 } |
320 | |
321 if (request->last_dir_entry) | |
322 { | |
323 g_free (request->last_dir_entry); | |
324 request->last_dir_entry = NULL; | |
325 request->last_dir_entry_len = 0; | |
326 } | |
327 | |
328 return (ret); | |
329 } | |
330 | |
331 | |
332 int | |
40 | 333 gftp_abort_transfer (gftp_request * request) |
334 { | |
84 | 335 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
40 | 336 |
337 if (request->abort_transfer == NULL) | |
84 | 338 return (GFTP_EFATAL); |
40 | 339 |
340 return (request->abort_transfer (request)); | |
341 } | |
342 | |
343 | |
344 int | |
1 | 345 gftp_list_files (gftp_request * request) |
346 { | |
473 | 347 char *remote_lc_time, *locret; |
58 | 348 int fd; |
1 | 349 |
84 | 350 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1 | 351 |
473 | 352 gftp_lookup_request_option (request, "remote_lc_time", &remote_lc_time); |
353 if (remote_lc_time != NULL && *remote_lc_time != '\0') | |
354 locret = setlocale (LC_TIME, remote_lc_time); | |
355 else | |
356 locret = setlocale (LC_TIME, NULL); | |
357 | |
358 if (locret == NULL) | |
359 { | |
360 locret = setlocale (LC_TIME, NULL); | |
361 request->logging_function (gftp_logging_misc, request, | |
362 _("Error setting LC_TIME to '%s'. Falling back to '%s'\n"), | |
363 remote_lc_time, locret); | |
364 } | |
365 | |
1 | 366 request->cached = 0; |
58 | 367 if (request->use_cache && (fd = gftp_find_cache_entry (request)) > 0) |
1 | 368 { |
186 | 369 request->logging_function (gftp_logging_misc, request, |
473 | 370 _("Loading directory listing %s from cache (LC_TIME=%s)\n"), |
371 request->directory, locret); | |
1 | 372 |
373 request->cachefd = fd; | |
374 request->cached = 1; | |
375 return (0); | |
376 } | |
377 else if (request->use_cache) | |
378 { | |
473 | 379 request->logging_function (gftp_logging_misc, request, |
380 _("Loading directory listing %s from server (LC_TIME=%s)\n"), | |
381 request->directory, locret); | |
382 | |
1 | 383 request->cachefd = gftp_new_cache_entry (request); |
384 request->cached = 0; | |
385 } | |
386 | |
387 if (request->list_files == NULL) | |
84 | 388 return (GFTP_EFATAL); |
473 | 389 |
1 | 390 return (request->list_files (request)); |
391 } | |
392 | |
393 | |
184 | 394 #if GLIB_MAJOR_VERSION > 1 |
291 | 395 |
184 | 396 static char * |
423 | 397 _gftp_get_next_charset (char **curpos) |
184 | 398 { |
399 char *ret, *endpos; | |
400 | |
401 if (**curpos == '\0') | |
402 return (NULL); | |
403 | |
404 ret = *curpos; | |
185 | 405 if ((endpos = strchr (*curpos, ',')) == NULL) |
184 | 406 *curpos += strlen (*curpos); |
407 else | |
408 { | |
409 *endpos = '\0'; | |
423 | 410 *curpos = endpos + 1; |
184 | 411 } |
412 | |
413 return (ret); | |
414 } | |
415 | |
416 | |
186 | 417 char * |
291 | 418 gftp_string_to_utf8 (gftp_request * request, const char *str) |
184 | 419 { |
423 | 420 char *ret, *remote_charsets, *stpos, *cur_charset, *tempstr; |
184 | 421 gsize bread, bwrite; |
422 GError * error; | |
423 | |
188 | 424 if (request == NULL) |
425 return (NULL); | |
426 | |
184 | 427 if (request->iconv_initialized) |
428 return (g_convert_with_iconv (str, -1, request->iconv, &bread, &bwrite, | |
429 &error)); | |
291 | 430 else if (g_utf8_validate (str, -1, NULL)) |
431 return (NULL); | |
184 | 432 |
423 | 433 gftp_lookup_request_option (request, "remote_charsets", &tempstr); |
434 if (*tempstr == '\0') | |
184 | 435 { |
436 error = NULL; | |
437 if ((ret = g_locale_to_utf8 (str, -1, &bread, &bwrite, &error)) != NULL) | |
438 return (ret); | |
439 | |
440 return (NULL); | |
441 } | |
442 | |
423 | 443 remote_charsets = g_strdup (tempstr); |
184 | 444 ret = NULL; |
445 stpos = remote_charsets; | |
423 | 446 while ((cur_charset = _gftp_get_next_charset (&stpos)) != NULL) |
184 | 447 { |
448 if ((request->iconv = g_iconv_open ("UTF-8", cur_charset)) == (GIConv) -1) | |
449 continue; | |
450 | |
451 error = NULL; | |
452 if ((ret = g_convert_with_iconv (str, -1, request->iconv, &bread, &bwrite, | |
453 &error)) == NULL) | |
454 { | |
455 g_iconv_close (request->iconv); | |
456 request->iconv = NULL; | |
457 continue; | |
458 } | |
459 else | |
460 { | |
461 request->iconv_initialized = 1; | |
462 break; | |
463 } | |
464 } | |
465 | |
423 | 466 g_free (remote_charsets); |
467 | |
184 | 468 return (ret); |
469 } | |
291 | 470 |
471 | |
472 char * | |
473 gftp_string_from_utf8 (gftp_request * request, const char *str) | |
474 { | |
423 | 475 char *ret, *remote_charsets, *stpos, *cur_charset, *tempstr; |
291 | 476 gsize bread, bwrite; |
477 GError * error; | |
478 | |
479 if (request == NULL) | |
480 return (NULL); | |
481 | |
482 if (request->iconv_initialized) | |
483 return (g_convert_with_iconv (str, -1, request->iconv, &bread, &bwrite, | |
484 &error)); | |
485 else if (g_utf8_validate (str, -1, NULL)) | |
486 return (NULL); | |
487 | |
423 | 488 gftp_lookup_request_option (request, "remote_charsets", &tempstr); |
489 if (*tempstr == '\0') | |
291 | 490 { |
491 error = NULL; | |
492 if ((ret = g_locale_from_utf8 (str, -1, &bread, &bwrite, &error)) != NULL) | |
493 return (ret); | |
494 | |
495 return (NULL); | |
496 } | |
497 | |
423 | 498 remote_charsets = g_strdup (tempstr); |
291 | 499 ret = NULL; |
500 stpos = remote_charsets; | |
423 | 501 while ((cur_charset = _gftp_get_next_charset (&stpos)) != NULL) |
291 | 502 { |
503 if ((request->iconv = g_iconv_open (cur_charset, "UTF-8")) == (GIConv) -1) | |
504 continue; | |
505 | |
506 error = NULL; | |
507 if ((ret = g_convert_with_iconv (str, -1, request->iconv, &bread, &bwrite, | |
508 &error)) == NULL) | |
509 { | |
510 g_iconv_close (request->iconv); | |
511 request->iconv = NULL; | |
512 continue; | |
513 } | |
514 else | |
515 { | |
516 request->iconv_initialized = 1; | |
517 break; | |
518 } | |
519 } | |
520 | |
423 | 521 g_free (remote_charsets); |
522 | |
291 | 523 return (ret); |
524 } | |
525 | |
526 #else | |
527 | |
528 char * | |
529 gftp_string_to_utf8 (gftp_request * request, const char *str) | |
530 { | |
531 return (NULL); | |
532 } | |
533 | |
534 | |
535 char * | |
536 gftp_string_from_utf8 (gftp_request * request, const char *str) | |
537 { | |
538 return (NULL); | |
539 } | |
540 | |
184 | 541 #endif |
542 | |
543 | |
1 | 544 int |
377 | 545 gftp_get_next_file (gftp_request * request, const char *filespec, |
546 gftp_file * fle) | |
1 | 547 { |
58 | 548 int fd, ret; |
1 | 549 |
84 | 550 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1 | 551 |
552 if (request->get_next_file == NULL) | |
84 | 553 return (GFTP_EFATAL); |
1 | 554 |
58 | 555 if (request->cached && request->cachefd > 0) |
1 | 556 fd = request->cachefd; |
557 else | |
558 fd = request->datafd; | |
559 | |
560 memset (fle, 0, sizeof (*fle)); | |
561 do | |
562 { | |
563 gftp_file_destroy (fle); | |
564 ret = request->get_next_file (request, fle, fd); | |
565 | |
291 | 566 if (ret >= 0 && fle->file != NULL) |
184 | 567 fle->utf8_file = gftp_string_to_utf8 (request, fle->file); |
45 | 568 |
60 | 569 if (ret >= 0 && !request->cached && request->cachefd > 0 && |
1 | 570 request->last_dir_entry != NULL) |
571 { | |
168 | 572 if (gftp_fd_write (request, request->last_dir_entry, |
60 | 573 request->last_dir_entry_len, request->cachefd) < 0) |
1 | 574 { |
186 | 575 request->logging_function (gftp_logging_error, request, |
1 | 576 _("Error: Cannot write to cache: %s\n"), |
577 g_strerror (errno)); | |
60 | 578 close (request->cachefd); |
579 request->cachefd = -1; | |
1 | 580 } |
581 } | |
582 } while (ret > 0 && !gftp_match_filespec (fle->file, filespec)); | |
583 | |
584 return (ret); | |
585 } | |
586 | |
587 | |
588 int | |
243 | 589 gftp_parse_bookmark (gftp_request * request, gftp_request * local_request, |
275 | 590 const char * bookmark, int *refresh_local) |
87 | 591 { |
592 gftp_logging_func logging_function; | |
122 | 593 gftp_bookmarks_var * tempentry; |
594 char *default_protocol; | |
173 | 595 int i, init_ret; |
87 | 596 |
597 g_return_val_if_fail (request != NULL, GFTP_EFATAL); | |
598 g_return_val_if_fail (bookmark != NULL, GFTP_EFATAL); | |
599 | |
600 logging_function = request->logging_function; | |
601 gftp_request_destroy (request, 0); | |
602 request->logging_function = logging_function; | |
603 | |
122 | 604 if ((tempentry = g_hash_table_lookup (gftp_bookmarks_htable, |
605 bookmark)) == NULL) | |
87 | 606 { |
186 | 607 request->logging_function (gftp_logging_error, request, |
87 | 608 _("Error: Could not find bookmark %s\n"), |
609 bookmark); | |
610 return (GFTP_EFATAL); | |
611 } | |
612 else if (tempentry->hostname == NULL || *tempentry->hostname == '\0') | |
613 { | |
186 | 614 request->logging_function (gftp_logging_error, request, |
87 | 615 _("Bookmarks Error: The bookmark entry %s does not have a hostname\n"), bookmark); |
616 return (GFTP_EFATAL); | |
617 } | |
618 | |
619 if (tempentry->user != NULL) | |
620 gftp_set_username (request, tempentry->user); | |
621 | |
622 if (tempentry->pass != NULL) | |
122 | 623 gftp_set_password (request, tempentry->pass); |
87 | 624 |
625 if (tempentry->acct != NULL) | |
626 gftp_set_account (request, tempentry->acct); | |
627 | |
628 gftp_set_hostname (request, tempentry->hostname); | |
629 gftp_set_directory (request, tempentry->remote_dir); | |
630 gftp_set_port (request, tempentry->port); | |
631 | |
243 | 632 if (local_request != NULL && |
633 tempentry->local_dir != NULL && | |
634 *tempentry->local_dir != '\0') | |
275 | 635 { |
636 gftp_set_directory (local_request, tempentry->local_dir); | |
637 *refresh_local = 1; | |
638 } | |
639 else | |
640 *refresh_local = 0; | |
243 | 641 |
87 | 642 for (i = 0; gftp_protocols[i].name; i++) |
643 { | |
644 if (strcmp (gftp_protocols[i].name, tempentry->protocol) == 0) | |
645 { | |
173 | 646 if ((init_ret = gftp_protocols[i].init (request)) < 0) |
647 { | |
648 gftp_request_destroy (request, 0); | |
649 return (init_ret); | |
650 } | |
87 | 651 break; |
652 } | |
653 } | |
654 | |
122 | 655 if (gftp_protocols[i].name == NULL) |
87 | 656 { |
122 | 657 gftp_lookup_request_option (request, "default_protocol", |
658 &default_protocol); | |
659 | |
125 | 660 if (default_protocol != NULL && *default_protocol != '\0') |
87 | 661 { |
122 | 662 for (i = 0; gftp_protocols[i].url_prefix; i++) |
663 { | |
664 if (strcmp (gftp_protocols[i].name, default_protocol) == 0) | |
665 break; | |
666 } | |
87 | 667 } |
668 | |
669 if (gftp_protocols[i].url_prefix == NULL) | |
670 i = GFTP_FTP_NUM; | |
671 } | |
672 | |
199 | 673 gftp_copy_local_options (&request->local_options_vars, |
674 &request->local_options_hash, | |
429 | 675 &request->num_local_options_vars, |
199 | 676 tempentry->local_options_vars, |
677 tempentry->num_local_options_vars); | |
678 | |
173 | 679 if ((init_ret = gftp_protocols[i].init (request)) < 0) |
680 { | |
681 gftp_request_destroy (request, 0); | |
682 return (init_ret); | |
683 } | |
684 | |
87 | 685 return (0); |
686 } | |
687 | |
688 | |
689 int | |
1 | 690 gftp_parse_url (gftp_request * request, const char *url) |
691 { | |
168 | 692 char *pos, *endpos, *endhostpos, tempchar, *default_protocol, *stpos; |
67 | 693 gftp_logging_func logging_function; |
173 | 694 int len, i, init_ret; |
168 | 695 const char *cpos; |
1 | 696 |
84 | 697 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
698 g_return_val_if_fail (url != NULL, GFTP_EFATAL); | |
1 | 699 |
67 | 700 logging_function = request->logging_function; |
701 gftp_request_destroy (request, 0); | |
702 request->logging_function = logging_function; | |
703 | |
168 | 704 for (cpos = url; *cpos == ' '; cpos++); |
705 stpos = g_strdup (cpos); | |
706 for (pos = stpos + strlen (stpos) - 1; *pos == ' '; pos--) | |
707 *pos = '\0'; | |
1 | 708 |
122 | 709 i = GFTP_FTP_NUM; |
710 | |
1 | 711 if ((pos = strstr (stpos, "://")) != NULL) |
712 { | |
713 *pos = '\0'; | |
714 | |
715 for (i = 0; gftp_protocols[i].url_prefix; i++) | |
716 { | |
717 if (strcmp (gftp_protocols[i].url_prefix, stpos) == 0) | |
718 break; | |
719 } | |
720 | |
721 if (gftp_protocols[i].url_prefix == NULL) | |
168 | 722 { |
173 | 723 request->logging_function (gftp_logging_misc, NULL, |
724 _("The protocol '%s' is currently not supported.\n"), | |
725 stpos); | |
168 | 726 g_free (stpos); |
727 return (GFTP_EFATAL); | |
728 } | |
173 | 729 |
730 *pos = ':'; | |
1 | 731 } |
732 else | |
733 { | |
122 | 734 gftp_lookup_request_option (request, "default_protocol", |
735 &default_protocol); | |
736 | |
125 | 737 if (default_protocol != NULL && *default_protocol != '\0') |
1 | 738 { |
122 | 739 for (i = 0; gftp_protocols[i].url_prefix; i++) |
740 { | |
741 if (strcmp (gftp_protocols[i].name, default_protocol) == 0) | |
742 break; | |
743 } | |
1 | 744 } |
122 | 745 } |
1 | 746 |
122 | 747 if (gftp_protocols[i].url_prefix == NULL) |
748 i = GFTP_FTP_NUM; | |
1 | 749 |
173 | 750 if ((init_ret = gftp_protocols[i].init (request)) < 0) |
751 { | |
752 gftp_request_destroy (request, 0); | |
753 return (init_ret); | |
754 } | |
1 | 755 |
756 if (request->parse_url != NULL) | |
168 | 757 { |
758 g_free (stpos); | |
759 return (request->parse_url (request, url)); | |
760 } | |
761 | |
762 pos = stpos; | |
763 len = strlen (request->url_prefix); | |
764 if (strncmp (pos, request->url_prefix, len) == 0 && | |
765 strncmp (pos + len, "://", 3) == 0) | |
766 pos += len + 3; | |
1 | 767 |
768 if (i == GFTP_LOCAL_NUM) | |
769 { | |
367 | 770 for (; *pos == ' ' || *pos == '\t'; pos++); |
168 | 771 request->directory = g_strdup (pos); |
772 g_free (stpos); | |
1 | 773 return (0); |
774 } | |
775 | |
182 | 776 if ((endhostpos = strrchr (pos, '@')) != NULL) |
1 | 777 { |
778 /* A user/password was entered */ | |
779 if ((endpos = strchr (pos, ':')) == NULL || endhostpos < endpos) | |
168 | 780 { |
781 /* No password was entered */ | |
782 gftp_set_password (request, ""); | |
783 endpos = endhostpos; | |
784 } | |
1 | 785 |
786 *endpos = '\0'; | |
787 gftp_set_username (request, pos); | |
788 | |
789 pos = endpos + 1; | |
790 if ((endpos = strchr (pos, '@')) != NULL) | |
168 | 791 { |
792 if (strchr (endpos + 1, '@') != NULL) | |
793 endpos = strchr (endpos + 1, '@'); | |
794 *endpos = '\0'; | |
795 gftp_set_password (request, pos); | |
1 | 796 |
168 | 797 pos = endpos + 1; |
798 } | |
1 | 799 } |
800 | |
801 /* Now get the hostname and an optional port and optional directory */ | |
802 endhostpos = pos + strlen (pos); | |
803 if ((endpos = strchr (pos, ':')) != NULL) | |
804 endhostpos = endpos; | |
805 else if ((endpos = strchr (pos, '/')) != NULL) | |
806 endhostpos = endpos; | |
807 tempchar = *endhostpos; | |
808 *endhostpos = '\0'; | |
809 gftp_set_hostname (request, pos); | |
810 *endhostpos = tempchar; | |
811 | |
812 if ((endpos = strchr (pos, ':')) != NULL) | |
813 { | |
814 /* A port was entered */ | |
815 pos = endpos + 1; | |
816 gftp_set_port (request, strtol (pos, NULL, 10)); | |
817 } | |
818 if ((endpos = strchr (pos, '/')) != NULL) | |
819 gftp_set_directory (request, endpos); | |
168 | 820 g_free (stpos); |
1 | 821 return (0); |
822 } | |
823 | |
824 | |
825 void | |
826 gftp_set_hostname (gftp_request * request, const char *hostname) | |
827 { | |
828 g_return_if_fail (request != NULL); | |
829 g_return_if_fail (hostname != NULL); | |
830 | |
831 if (request->hostname) | |
832 g_free (request->hostname); | |
124 | 833 request->hostname = g_strdup (hostname); |
1 | 834 } |
835 | |
836 | |
837 void | |
838 gftp_set_username (gftp_request * request, const char *username) | |
839 { | |
840 g_return_if_fail (request != NULL); | |
841 | |
842 if (request->username) | |
843 g_free (request->username); | |
169 | 844 |
845 if (username != NULL) | |
846 request->username = g_strdup (username); | |
847 else | |
848 request->username = NULL; | |
1 | 849 } |
850 | |
851 | |
852 void | |
853 gftp_set_password (gftp_request * request, const char *password) | |
854 { | |
855 g_return_if_fail (request != NULL); | |
856 | |
857 if (request->password) | |
858 g_free (request->password); | |
169 | 859 |
860 if (password != NULL) | |
861 request->password = g_strdup (password); | |
862 else | |
863 request->password = NULL; | |
1 | 864 } |
865 | |
866 | |
867 void | |
868 gftp_set_account (gftp_request * request, const char *account) | |
869 { | |
870 g_return_if_fail (request != NULL); | |
871 g_return_if_fail (account != NULL); | |
872 | |
873 if (request->account) | |
874 g_free (request->account); | |
124 | 875 request->account = g_strdup (account); |
1 | 876 } |
877 | |
878 | |
879 int | |
880 gftp_set_directory (gftp_request * request, const char *directory) | |
881 { | |
84 | 882 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
883 g_return_val_if_fail (directory != NULL, GFTP_EFATAL); | |
1 | 884 |
885 | |
169 | 886 if (request->datafd <= 0 && !request->always_connected) |
1 | 887 { |
888 if (directory != request->directory) | |
168 | 889 { |
890 if (request->directory) | |
891 g_free (request->directory); | |
892 request->directory = g_strdup (directory); | |
893 } | |
1 | 894 return (0); |
895 } | |
896 else if (request->chdir == NULL) | |
84 | 897 return (GFTP_EFATAL); |
1 | 898 return (request->chdir (request, directory)); |
899 } | |
900 | |
901 | |
902 void | |
903 gftp_set_port (gftp_request * request, unsigned int port) | |
904 { | |
905 g_return_if_fail (request != NULL); | |
906 | |
907 request->port = port; | |
908 } | |
909 | |
910 | |
911 int | |
912 gftp_remove_directory (gftp_request * request, const char *directory) | |
913 { | |
84 | 914 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1 | 915 |
916 if (request->rmdir == NULL) | |
84 | 917 return (GFTP_EFATAL); |
1 | 918 return (request->rmdir (request, directory)); |
919 } | |
920 | |
921 | |
922 int | |
923 gftp_remove_file (gftp_request * request, const char *file) | |
924 { | |
84 | 925 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1 | 926 |
927 if (request->rmfile == NULL) | |
84 | 928 return (GFTP_EFATAL); |
1 | 929 return (request->rmfile (request, file)); |
930 } | |
931 | |
932 | |
933 int | |
934 gftp_make_directory (gftp_request * request, const char *directory) | |
935 { | |
291 | 936 char *utf8; |
937 int ret; | |
938 | |
84 | 939 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1 | 940 |
941 if (request->mkdir == NULL) | |
84 | 942 return (GFTP_EFATAL); |
291 | 943 |
944 utf8 = gftp_string_from_utf8 (request, directory); | |
945 if (utf8 != NULL) | |
946 { | |
947 ret = request->mkdir (request, utf8); | |
948 g_free (utf8); | |
949 } | |
950 else | |
951 ret = request->mkdir (request, directory); | |
952 | |
953 return (ret); | |
1 | 954 } |
955 | |
956 | |
957 int | |
958 gftp_rename_file (gftp_request * request, const char *oldname, | |
168 | 959 const char *newname) |
1 | 960 { |
291 | 961 char *utf8; |
962 int ret; | |
963 | |
84 | 964 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1 | 965 |
966 if (request->rename == NULL) | |
84 | 967 return (GFTP_EFATAL); |
291 | 968 |
969 utf8 = gftp_string_from_utf8 (request, newname); | |
970 if (utf8 != NULL) | |
971 { | |
972 ret = request->rename (request, oldname, utf8); | |
973 g_free (utf8); | |
974 } | |
975 else | |
976 ret = request->rename (request, oldname, newname); | |
977 | |
978 return (ret); | |
1 | 979 } |
980 | |
981 | |
982 int | |
983 gftp_chmod (gftp_request * request, const char *file, int mode) | |
984 { | |
84 | 985 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1 | 986 |
987 if (request->chmod == NULL) | |
84 | 988 return (GFTP_EFATAL); |
1 | 989 return (request->chmod (request, file, mode)); |
990 } | |
991 | |
992 | |
993 int | |
994 gftp_set_file_time (gftp_request * request, const char *file, time_t datetime) | |
995 { | |
84 | 996 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1 | 997 |
998 if (request->set_file_time == NULL) | |
84 | 999 return (GFTP_EFATAL); |
1 | 1000 return (request->set_file_time (request, file, datetime)); |
1001 } | |
1002 | |
1003 | |
1004 char | |
478 | 1005 gftp_site_cmd (gftp_request * request, int specify_site, const char *command) |
1 | 1006 { |
84 | 1007 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1 | 1008 |
1009 if (request->site == NULL) | |
84 | 1010 return (GFTP_EFATAL); |
478 | 1011 return (request->site (request, specify_site, command)); |
1 | 1012 } |
1013 | |
1014 | |
58 | 1015 off_t |
1 | 1016 gftp_get_file_size (gftp_request * request, const char *filename) |
1017 { | |
1018 g_return_val_if_fail (request != NULL, 0); | |
1019 | |
1020 if (request->get_file_size == NULL) | |
1021 return (0); | |
1022 return (request->get_file_size (request, filename)); | |
1023 } | |
1024 | |
1025 | |
122 | 1026 static int |
1027 gftp_need_proxy (gftp_request * request, char *service, char *proxy_hostname, | |
1028 int proxy_port) | |
1 | 1029 { |
122 | 1030 gftp_config_list_vars * proxy_hosts; |
1 | 1031 gftp_proxy_hosts * hostname; |
460 | 1032 size_t hostlen, domlen; |
1 | 1033 unsigned char addy[4]; |
1034 struct sockaddr *addr; | |
1035 GList * templist; | |
1036 gint32 netaddr; | |
1037 char *pos; | |
1038 #if defined (HAVE_GETADDRINFO) && defined (HAVE_GAI_STRERROR) | |
1039 struct addrinfo hints; | |
1040 int port, errnum; | |
1041 char serv[8]; | |
122 | 1042 #endif |
1043 | |
218 | 1044 gftp_lookup_global_option ("dont_use_proxy", &proxy_hosts); |
122 | 1045 |
1046 if (proxy_hostname == NULL || *proxy_hostname == '\0') | |
1047 return (0); | |
1048 else if (proxy_hosts->list == NULL) | |
1049 return (proxy_hostname != NULL && | |
1050 *proxy_hostname != '\0'); | |
1 | 1051 |
1052 request->hostp = NULL; | |
122 | 1053 #if defined (HAVE_GETADDRINFO) && defined (HAVE_GAI_STRERROR) |
151 | 1054 request->free_hostp = 1; |
1 | 1055 memset (&hints, 0, sizeof (hints)); |
1056 hints.ai_flags = AI_CANONNAME; | |
146 | 1057 hints.ai_family = PF_UNSPEC; |
1 | 1058 hints.ai_socktype = SOCK_STREAM; |
1059 | |
122 | 1060 port = request->use_proxy ? proxy_port : request->port; |
1 | 1061 if (port == 0) |
1062 strcpy (serv, service); | |
1063 else | |
1064 snprintf (serv, sizeof (serv), "%d", port); | |
1065 | |
186 | 1066 request->logging_function (gftp_logging_misc, request, |
1 | 1067 _("Looking up %s\n"), request->hostname); |
1068 | |
1069 if ((errnum = getaddrinfo (request->hostname, serv, &hints, | |
1070 &request->hostp)) != 0) | |
1071 { | |
186 | 1072 request->logging_function (gftp_logging_error, request, |
1 | 1073 _("Cannot look up hostname %s: %s\n"), |
1074 request->hostname, gai_strerror (errnum)); | |
84 | 1075 return (GFTP_ERETRYABLE); |
1 | 1076 } |
1077 | |
1078 addr = request->hostp->ai_addr; | |
1079 | |
1080 #else /* !HAVE_GETADDRINFO */ | |
186 | 1081 request->logging_function (gftp_logging_misc, request, |
1 | 1082 _("Looking up %s\n"), request->hostname); |
1083 | |
1084 if (!(request->hostp = r_gethostbyname (request->hostname, &request->host, | |
1085 NULL))) | |
1086 { | |
186 | 1087 request->logging_function (gftp_logging_error, request, |
1 | 1088 _("Cannot look up hostname %s: %s\n"), |
1089 request->hostname, g_strerror (errno)); | |
84 | 1090 return (GFTP_ERETRYABLE); |
1 | 1091 } |
1092 | |
1093 addr = (struct sockaddr *) request->host.h_addr_list[0]; | |
1094 | |
1095 #endif /* HAVE_GETADDRINFO */ | |
1096 | |
122 | 1097 templist = proxy_hosts->list; |
1 | 1098 while (templist != NULL) |
1099 { | |
1100 hostname = templist->data; | |
460 | 1101 if (hostname->domain != NULL) |
168 | 1102 { |
460 | 1103 hostlen = strlen (request->hostname); |
1104 domlen = strlen (hostname->domain); | |
1105 if (hostlen > domlen) | |
1106 { | |
1107 pos = request->hostname + hostlen - domlen; | |
1108 if (strcmp (hostname->domain, pos) == 0) | |
1109 return (0); | |
1110 } | |
168 | 1111 } |
1 | 1112 |
1113 if (hostname->ipv4_network_address != 0) | |
168 | 1114 { |
1115 memcpy (addy, addr, sizeof (addy)); | |
1116 netaddr = | |
1117 (((addy[0] & 0xff) << 24) | ((addy[1] & 0xff) << 16) | | |
1118 ((addy[2] & 0xff) << 8) | (addy[3] & 0xff)) & | |
1 | 1119 hostname->ipv4_netmask; |
168 | 1120 if (netaddr == hostname->ipv4_network_address) |
1121 return (0); | |
1122 } | |
1 | 1123 templist = templist->next; |
1124 } | |
1125 | |
122 | 1126 return (proxy_hostname != NULL && *proxy_hostname != '\0'); |
1 | 1127 } |
1128 | |
1129 | |
48 | 1130 static char * |
1131 copy_token (char **dest, char *source) | |
1 | 1132 { |
48 | 1133 /* This function is used internally by gftp_parse_ls () */ |
1134 char *endpos, savepos; | |
1 | 1135 |
48 | 1136 endpos = source; |
1137 while (*endpos != ' ' && *endpos != '\t' && *endpos != '\0') | |
1138 endpos++; | |
1139 if (*endpos == '\0') | |
1140 return (NULL); | |
1 | 1141 |
48 | 1142 savepos = *endpos; |
1143 *endpos = '\0'; | |
1144 *dest = g_malloc (endpos - source + 1); | |
1145 strcpy (*dest, source); | |
1146 *endpos = savepos; | |
1 | 1147 |
48 | 1148 /* Skip the blanks till we get to the next entry */ |
1149 source = endpos + 1; | |
1150 while ((*source == ' ' || *source == '\t') && *source != '\0') | |
1151 source++; | |
1152 return (source); | |
1153 } | |
1 | 1154 |
1155 | |
48 | 1156 static char * |
1157 goto_next_token (char *pos) | |
1158 { | |
1159 while (*pos != ' ' && *pos != '\t' && *pos != '\0') | |
1160 pos++; | |
1 | 1161 |
48 | 1162 if (pos == '\0') |
1163 return (pos); | |
1 | 1164 |
48 | 1165 while ((*pos == ' ' || *pos == '\t') && *pos != '\0') |
1166 pos++; | |
1167 | |
1168 return (pos); | |
1 | 1169 } |
1170 | |
1171 | |
485 | 1172 static time_t |
1173 parse_vms_time (char *str, char **endpos) | |
1174 { | |
1175 struct tm curtime; | |
1176 time_t ret; | |
1177 | |
1178 /* 8-JUN-2004 13:04:14 */ | |
1179 memset (&curtime, 0, sizeof (curtime)); | |
1180 | |
1181 *endpos = strptime (str, "%d-%b-%Y %H:%M:%S", &curtime); | |
1182 if (*endpos == NULL) | |
1183 *endpos = strptime (str, "%d-%b-%Y %H:%M", &curtime); | |
1184 | |
1185 if (*endpos != NULL) | |
1186 { | |
1187 ret = mktime (&curtime); | |
1188 for (; **endpos == ' ' || **endpos == '\t'; (*endpos)++); | |
1189 } | |
1190 else | |
1191 { | |
1192 ret = 0; | |
1193 *endpos = goto_next_token (str); | |
1194 if (*endpos != NULL) | |
1195 *endpos = goto_next_token (*endpos); | |
1196 } | |
1197 | |
1198 return (ret); | |
1199 } | |
1200 | |
1201 | |
102 | 1202 time_t |
1203 parse_time (char *str, char **endpos) | |
1 | 1204 { |
102 | 1205 struct tm curtime, *loctime; |
105 | 1206 time_t t, ret; |
102 | 1207 char *tmppos; |
460 | 1208 size_t slen; |
260 | 1209 int i, num; |
1 | 1210 |
460 | 1211 slen = strlen (str); |
102 | 1212 memset (&curtime, 0, sizeof (curtime)); |
1213 curtime.tm_isdst = -1; | |
460 | 1214 |
1215 if (slen > 4 && isdigit ((int) str[0]) && str[2] == '-' && | |
260 | 1216 isdigit ((int) str[3])) |
1 | 1217 { |
1218 /* This is how DOS will return the date/time */ | |
1219 /* 07-06-99 12:57PM */ | |
1220 | |
102 | 1221 tmppos = strptime (str, "%m-%d-%y %I:%M%p", &curtime); |
1 | 1222 } |
460 | 1223 else if (slen > 4 && isdigit ((int) str[0]) && str[2] == '-' && |
260 | 1224 isalpha (str[3])) |
105 | 1225 { |
1226 /* 10-Jan-2003 09:14 */ | |
1227 tmppos = strptime (str, "%d-%h-%Y %H:%M", &curtime); | |
1228 } | |
460 | 1229 else if (slen > 4 && isdigit ((int) str[0]) && str[4] == '/') |
358 | 1230 { |
1231 /* 2003/12/25 */ | |
1232 tmppos = strptime (str, "%Y/%m/%d", &curtime); | |
1233 } | |
1 | 1234 else |
1235 { | |
1236 /* This is how most UNIX, Novell, and MacOS ftp servers send their time */ | |
102 | 1237 /* Jul 06 12:57 or Jul 6 1999 */ |
1 | 1238 |
102 | 1239 if (strchr (str, ':') != NULL) |
1240 { | |
1241 tmppos = strptime (str, "%h %d %H:%M", &curtime); | |
1242 t = time (NULL); | |
1243 loctime = localtime (&t); | |
359 | 1244 |
1245 if (curtime.tm_mon > loctime->tm_mon) | |
1246 curtime.tm_year = loctime->tm_year - 1; | |
1247 else | |
1248 curtime.tm_year = loctime->tm_year; | |
102 | 1249 } |
1250 else | |
1251 tmppos = strptime (str, "%h %d %Y", &curtime); | |
1252 } | |
1 | 1253 |
105 | 1254 if (tmppos != NULL) |
1255 ret = mktime (&curtime); | |
1256 else | |
1257 ret = 0; | |
1258 | |
102 | 1259 if (endpos != NULL) |
105 | 1260 { |
1261 if (tmppos == NULL) | |
1262 { | |
260 | 1263 /* We cannot parse this date format. So, just skip this date field |
1264 and continue to the next token. This is mainly for the HTTP | |
1265 support */ | |
1266 | |
1267 *endpos = str; | |
1268 for (num = 0; num < 2 && **endpos != '\0'; num++) | |
1269 { | |
1270 for (i=0; | |
1271 (*endpos)[i] != ' ' && (*endpos)[i] != '\t' && | |
1272 (*endpos)[i] != '\0'; | |
1273 i++); | |
1274 *endpos += i; | |
1275 | |
1276 for (i=0; (*endpos)[i] == ' ' || (*endpos)[i] == '\t'; i++); | |
1277 *endpos += i; | |
1278 } | |
105 | 1279 } |
1280 else | |
1281 *endpos = tmppos; | |
1282 } | |
1 | 1283 |
281 | 1284 return (ret); |
1 | 1285 } |
1286 | |
1287 | |
107 | 1288 static void |
1289 gftp_parse_vms_attribs (char *dest, char **src) | |
1290 { | |
1291 char *endpos; | |
1292 | |
1293 if (*src == NULL) | |
1294 return; | |
1295 | |
1296 if ((endpos = strchr (*src, ',')) != NULL) | |
1297 *endpos = '\0'; | |
1298 | |
1299 if (strchr (*src, 'R') != NULL) | |
1300 *dest = 'r'; | |
1301 if (strchr (*src, 'W') != NULL) | |
1302 *(dest + 1) = 'w'; | |
1303 if (strchr (*src, 'E') != NULL) | |
1304 *(dest + 2) = 'x'; | |
1305 | |
1306 *src = endpos + 1; | |
1307 } | |
1308 | |
1309 | |
1310 static int | |
485 | 1311 gftp_parse_ls_vms (gftp_request * request, int fd, char *str, gftp_file * fle) |
107 | 1312 { |
485 | 1313 char *curpos, *endpos, tempstr[1024]; |
1314 int multiline; | |
1315 ssize_t len; | |
107 | 1316 |
1317 /* .PINE-DEBUG1;1 9 21-AUG-2002 20:06 [MYERSRG] (RWED,RWED,,) */ | |
1318 /* WWW.DIR;1 1 23-NOV-1999 05:47 [MYERSRG] (RWE,RWE,RE,E) */ | |
1319 | |
485 | 1320 /* Multiline VMS |
1321 $MAIN.TPU$JOURNAL;1 | |
1322 1/18 8-JUN-2004 13:04:14 [NUCLEAR,FISSION] (RWED,RWED,RE,) | |
1323 TCPIP$FTP_SERVER.LOG;29 | |
1324 0/18 8-JUN-2004 14:42:04 [NUCLEAR,FISSION] (RWED,RWED,RE,) | |
1325 TCPIP$FTP_SERVER.LOG;28 | |
1326 5/18 8-JUN-2004 13:05:11 [NUCLEAR,FISSION] (RWED,RWED,RE,) | |
1327 TCPIP$FTP_SERVER.LOG;27 | |
1328 5/18 8-JUN-2004 13:03:51 [NUCLEAR,FISSION] (RWED,RWED,RE,) */ | |
1329 | |
107 | 1330 if ((curpos = strchr (str, ';')) == NULL) |
1331 return (GFTP_EFATAL); | |
1332 | |
485 | 1333 multiline = strchr (str, ' ') == NULL; |
1334 | |
107 | 1335 *curpos = '\0'; |
1336 if (strlen (str) > 4 && strcmp (curpos - 4, ".DIR") == 0) | |
1337 { | |
1338 fle->isdir = 1; | |
485 | 1339 fle->attribs = g_strdup ("d---------"); |
107 | 1340 *(curpos - 4) = '\0'; |
1341 } | |
358 | 1342 else |
485 | 1343 fle->attribs = g_strdup ("----------"); |
107 | 1344 |
1345 fle->file = g_strdup (str); | |
1346 | |
485 | 1347 if (multiline) |
1348 { | |
1349 if (request->get_next_dirlist_line == NULL) | |
1350 return (GFTP_EFATAL); | |
1351 | |
1352 len = request->get_next_dirlist_line (request, fd, tempstr, | |
1353 sizeof (tempstr)); | |
1354 if (len <= 0) | |
1355 return ((int) len); | |
1356 | |
1357 for (curpos = tempstr; *curpos == ' ' || *curpos == '\t'; curpos++); | |
1358 } | |
1359 else | |
1360 curpos = goto_next_token (curpos + 1); | |
1361 | |
244 | 1362 fle->size = gftp_parse_file_size (curpos) * 512; /* Is this correct? */ |
107 | 1363 |
1364 curpos = goto_next_token (curpos); | |
1365 | |
485 | 1366 fle->datetime = parse_vms_time (curpos, &curpos); |
1367 | |
107 | 1368 if (*curpos != '[') |
1369 return (GFTP_EFATAL); | |
485 | 1370 |
107 | 1371 if ((endpos = strchr (curpos, ']')) == NULL) |
1372 return (GFTP_EFATAL); | |
1373 | |
1374 curpos = goto_next_token (endpos + 1); | |
1375 if ((curpos = strchr (curpos, ',')) == NULL) | |
1376 return (0); | |
1377 curpos++; | |
1378 | |
1379 gftp_parse_vms_attribs (fle->attribs + 1, &curpos); | |
1380 gftp_parse_vms_attribs (fle->attribs + 4, &curpos); | |
1381 gftp_parse_vms_attribs (fle->attribs + 7, &curpos); | |
1382 | |
485 | 1383 fle->user = g_strdup (""); |
1384 fle->group = g_strdup (""); | |
1385 | |
107 | 1386 return (0); |
1387 } | |
358 | 1388 |
1389 | |
1390 static int | |
1391 gftp_parse_ls_mvs (char *str, gftp_file * fle) | |
1392 { | |
1393 char *curpos; | |
1394 | |
1395 /* Volume Unit Referred Ext Used Recfm Lrecl BlkSz Dsorg Dsname */ | |
1396 /* SVI52A 3390 2003/12/10 8 216 FB 80 27920 PS CARDS.DELETES */ | |
1397 /* SVI528 3390 2003/12/12 1 5 FB 80 24000 PO CLIST */ | |
1398 | |
1399 curpos = goto_next_token (str + 1); | |
1400 if (curpos == NULL) | |
1401 return (GFTP_EFATAL); | |
1402 | |
1403 curpos = goto_next_token (curpos + 1); | |
1404 if (curpos == NULL) | |
1405 return (GFTP_EFATAL); | |
1406 | |
479 | 1407 fle->datetime = parse_time (curpos, &curpos); |
1408 | |
1409 curpos = goto_next_token (curpos); | |
1410 if (curpos == NULL) | |
358 | 1411 return (GFTP_EFATAL); |
1412 | |
1413 curpos = goto_next_token (curpos + 1); | |
1414 if (curpos == NULL) | |
1415 return (GFTP_EFATAL); | |
1416 | |
1417 fle->size = gftp_parse_file_size (curpos) * 55996; | |
1418 curpos = goto_next_token (curpos + 1); | |
1419 if (curpos == NULL) | |
1420 return (GFTP_EFATAL); | |
1421 | |
1422 curpos = goto_next_token (curpos + 1); | |
1423 if (curpos == NULL) | |
1424 return (GFTP_EFATAL); | |
1425 | |
1426 curpos = goto_next_token (curpos + 1); | |
1427 if (curpos == NULL) | |
1428 return (GFTP_EFATAL); | |
1429 | |
1430 curpos = goto_next_token (curpos + 1); | |
1431 if (curpos == NULL) | |
1432 return (GFTP_EFATAL); | |
1433 | |
1434 if (strncmp (curpos, "PS", 2) == 0) | |
1435 fle->attribs = g_strdup ("-rw-r--r--"); | |
1436 else if (strncmp (curpos, "PO", 2) == 0) | |
1437 fle->attribs = g_strdup ("drwxr-xr-x"); | |
1438 else | |
1439 return (GFTP_EFATAL); | |
1440 | |
1441 curpos = goto_next_token (curpos + 1); | |
1442 | |
1443 fle->user = g_strdup (_("unknown")); | |
1444 fle->group = g_strdup (_("unknown")); | |
1445 fle->file = g_strdup (curpos); | |
1446 | |
1447 return (0); | |
1448 } | |
107 | 1449 |
1450 | |
1 | 1451 static int |
1452 gftp_parse_ls_eplf (char *str, gftp_file * fle) | |
1453 { | |
1454 char *startpos; | |
358 | 1455 int isdir = 0; |
1 | 1456 |
1457 startpos = str; | |
1458 while (startpos) | |
1459 { | |
1460 startpos++; | |
1461 switch (*startpos) | |
168 | 1462 { |
1463 case '/': | |
358 | 1464 isdir = 1; |
168 | 1465 break; |
1466 case 's': | |
244 | 1467 fle->size = gftp_parse_file_size (startpos + 1); |
168 | 1468 break; |
1469 case 'm': | |
1470 fle->datetime = strtol (startpos + 1, NULL, 10); | |
1471 break; | |
1472 } | |
1 | 1473 startpos = strchr (startpos, ','); |
1474 } | |
358 | 1475 |
1 | 1476 if ((startpos = strchr (str, 9)) == NULL) |
84 | 1477 return (GFTP_EFATAL); |
358 | 1478 |
1479 if (isdir) | |
1480 fle->attribs = g_strdup ("drwxr-xr-x"); | |
1481 else | |
1482 fle->attribs = g_strdup ("-rw-r--r--"); | |
1483 | |
124 | 1484 fle->file = g_strdup (startpos + 1); |
1485 fle->user = g_strdup (_("unknown")); | |
1486 fle->group = g_strdup (_("unknown")); | |
1 | 1487 return (0); |
1488 } | |
1489 | |
1490 | |
1491 static int | |
460 | 1492 gftp_parse_ls_unix (gftp_request * request, char *str, size_t slen, |
1493 gftp_file * fle) | |
1 | 1494 { |
91 | 1495 char *endpos, *startpos, *pos; |
1496 int cols; | |
1497 | |
1498 /* If there is no space between the attribs and links field, just make one */ | |
460 | 1499 if (slen > 10) |
91 | 1500 str[10] = ' '; |
1501 | |
1502 /* Determine the number of columns */ | |
1503 cols = 0; | |
1504 pos = str; | |
1505 while (*pos != '\0') | |
1506 { | |
1507 while (*pos != '\0' && *pos != ' ' && *pos != '\t') | |
1508 { | |
1509 if (*pos == ':') | |
1510 break; | |
1511 pos++; | |
1512 } | |
1513 | |
1514 cols++; | |
1515 | |
1516 if (*pos == ':') | |
1517 { | |
1518 cols++; | |
1519 break; | |
1520 } | |
1521 | |
1522 while (*pos == ' ' || *pos == '\t') | |
1523 pos++; | |
1524 } | |
1 | 1525 |
1526 startpos = str; | |
1527 /* Copy file attributes */ | |
1528 if ((startpos = copy_token (&fle->attribs, startpos)) == NULL) | |
84 | 1529 return (GFTP_EFATAL); |
1 | 1530 |
1531 if (cols >= 9) | |
1532 { | |
1533 /* Skip the number of links */ | |
1534 startpos = goto_next_token (startpos); | |
1535 | |
1536 /* Copy the user that owns this file */ | |
1537 if ((startpos = copy_token (&fle->user, startpos)) == NULL) | |
168 | 1538 return (GFTP_EFATAL); |
1 | 1539 |
1540 /* Copy the group that owns this file */ | |
1541 if ((startpos = copy_token (&fle->group, startpos)) == NULL) | |
168 | 1542 return (GFTP_EFATAL); |
1 | 1543 } |
1544 else | |
1545 { | |
124 | 1546 fle->group = g_strdup (_("unknown")); |
1 | 1547 if (cols == 8) |
168 | 1548 { |
1549 if ((startpos = copy_token (&fle->user, startpos)) == NULL) | |
1550 return (GFTP_EFATAL); | |
1551 } | |
1 | 1552 else |
124 | 1553 fle->user = g_strdup (_("unknown")); |
1 | 1554 startpos = goto_next_token (startpos); |
1555 } | |
1556 | |
281 | 1557 if (request->server_type == GFTP_DIRTYPE_CRAY) |
1 | 1558 { |
91 | 1559 /* See if this is a Cray directory listing. It has the following format: |
1560 drwx------ 2 feiliu g913 DK common 4096 Sep 24 2001 wv */ | |
1561 if (cols == 11 && strstr (str, "->") == NULL) | |
1562 { | |
1563 startpos = goto_next_token (startpos); | |
1564 startpos = goto_next_token (startpos); | |
1565 } | |
1 | 1566 } |
1567 | |
1568 /* See if this is a block or character device. We will store the major number | |
1569 in the high word and the minor number in the low word. */ | |
1570 if ((fle->attribs[0] == 'b' || fle->attribs[0] == 'u' || | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
1571 fle->attribs[0] == 'c') && |
1 | 1572 ((endpos = strchr (startpos, ',')) != NULL)) |
1573 { | |
1574 fle->size = strtol (startpos, NULL, 10) << 16; | |
1575 | |
1576 startpos = endpos + 1; | |
1577 while (*startpos == ' ') | |
168 | 1578 startpos++; |
1 | 1579 |
1580 /* Get the minor number */ | |
1581 if ((endpos = strchr (startpos, ' ')) == NULL) | |
168 | 1582 return (GFTP_EFATAL); |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
1583 fle->size |= strtol (startpos, NULL, 10) & 0xFF; |
1 | 1584 } |
1585 else | |
1586 { | |
1587 /* This is a regular file */ | |
1588 if ((endpos = strchr (startpos, ' ')) == NULL) | |
168 | 1589 return (GFTP_EFATAL); |
244 | 1590 fle->size = gftp_parse_file_size (startpos); |
1 | 1591 } |
1592 | |
1593 /* Skip the blanks till we get to the next entry */ | |
1594 startpos = endpos + 1; | |
1595 while (*startpos == ' ') | |
1596 startpos++; | |
1597 | |
479 | 1598 fle->datetime = parse_time (startpos, &startpos); |
1 | 1599 |
1600 /* Skip the blanks till we get to the next entry */ | |
1601 startpos = goto_next_token (startpos); | |
1602 | |
1603 /* Parse the filename. If this file is a symbolic link, remove the -> part */ | |
1604 if (fle->attribs[0] == 'l' && ((endpos = strstr (startpos, "->")) != NULL)) | |
1605 *(endpos - 1) = '\0'; | |
1606 | |
124 | 1607 fle->file = g_strdup (startpos); |
1 | 1608 |
1609 /* Uncomment this if you want to strip the spaces off of the end of the file. | |
1610 I don't want to do this by default since there are valid filenames with | |
1611 spaces at the end of them. Some broken FTP servers like the Paradyne IPC | |
1612 DSLAMS append a bunch of spaces at the end of the file. | |
1613 for (endpos = fle->file + strlen (fle->file) - 1; | |
1614 *endpos == ' '; | |
1615 *endpos-- = '\0'); | |
1616 */ | |
1617 | |
1618 return (0); | |
1619 } | |
1620 | |
1621 | |
1622 static int | |
1623 gftp_parse_ls_nt (char *str, gftp_file * fle) | |
1624 { | |
1625 char *startpos; | |
1626 | |
1627 startpos = str; | |
479 | 1628 fle->datetime = parse_time (startpos, &startpos); |
1 | 1629 |
124 | 1630 fle->user = g_strdup (_("unknown")); |
1631 fle->group = g_strdup (_("unknown")); | |
1 | 1632 |
1633 startpos = goto_next_token (startpos); | |
1634 if (startpos[0] == '<') | |
124 | 1635 fle->attribs = g_strdup ("drwxrwxrwx"); |
1 | 1636 else |
1637 { | |
124 | 1638 fle->attribs = g_strdup ("-rw-rw-rw-"); |
244 | 1639 fle->size = gftp_parse_file_size (startpos); |
1 | 1640 } |
124 | 1641 |
1 | 1642 startpos = goto_next_token (startpos); |
124 | 1643 fle->file = g_strdup (startpos); |
1 | 1644 return (0); |
1645 } | |
1646 | |
1647 | |
1648 static int | |
1649 gftp_parse_ls_novell (char *str, gftp_file * fle) | |
1650 { | |
1651 char *startpos; | |
1652 | |
1653 if (str[12] != ' ') | |
84 | 1654 return (GFTP_EFATAL); |
1 | 1655 str[12] = '\0'; |
124 | 1656 fle->attribs = g_strdup (str); |
1 | 1657 startpos = str + 13; |
1658 | |
1659 while ((*startpos == ' ' || *startpos == '\t') && *startpos != '\0') | |
1660 startpos++; | |
1661 | |
1662 if ((startpos = copy_token (&fle->user, startpos)) == NULL) | |
84 | 1663 return (GFTP_EFATAL); |
1 | 1664 |
124 | 1665 fle->group = g_strdup (_("unknown")); |
1 | 1666 |
244 | 1667 fle->size = gftp_parse_file_size (startpos); |
1 | 1668 |
1669 startpos = goto_next_token (startpos); | |
479 | 1670 fle->datetime = parse_time (startpos, &startpos); |
1 | 1671 |
1672 startpos = goto_next_token (startpos); | |
124 | 1673 fle->file = g_strdup (startpos); |
1 | 1674 return (0); |
1675 } | |
1676 | |
1677 | |
48 | 1678 int |
485 | 1679 gftp_parse_ls (gftp_request * request, const char *lsoutput, gftp_file * fle, |
1680 int fd) | |
1 | 1681 { |
107 | 1682 char *str, *endpos, tmpchar; |
1683 int result, is_vms; | |
91 | 1684 size_t len; |
48 | 1685 |
84 | 1686 g_return_val_if_fail (lsoutput != NULL, GFTP_EFATAL); |
1687 g_return_val_if_fail (fle != NULL, GFTP_EFATAL); | |
48 | 1688 |
124 | 1689 str = g_strdup (lsoutput); |
48 | 1690 memset (fle, 0, sizeof (*fle)); |
1 | 1691 |
91 | 1692 len = strlen (str); |
107 | 1693 if (len > 0 && str[len - 1] == '\n') |
91 | 1694 str[--len] = '\0'; |
1695 if (len > 0 && str[len - 1] == '\r') | |
1696 str[--len] = '\0'; | |
39 | 1697 |
91 | 1698 switch (request->server_type) |
1699 { | |
122 | 1700 case GFTP_DIRTYPE_CRAY: |
1701 case GFTP_DIRTYPE_UNIX: | |
460 | 1702 result = gftp_parse_ls_unix (request, str, len, fle); |
91 | 1703 break; |
122 | 1704 case GFTP_DIRTYPE_EPLF: |
91 | 1705 result = gftp_parse_ls_eplf (str, fle); |
1706 break; | |
122 | 1707 case GFTP_DIRTYPE_NOVELL: |
91 | 1708 result = gftp_parse_ls_novell (str, fle); |
1709 break; | |
122 | 1710 case GFTP_DIRTYPE_DOS: |
91 | 1711 result = gftp_parse_ls_nt (str, fle); |
1712 break; | |
122 | 1713 case GFTP_DIRTYPE_VMS: |
485 | 1714 result = gftp_parse_ls_vms (request, fd, str, fle); |
107 | 1715 break; |
358 | 1716 case GFTP_DIRTYPE_MVS: |
1717 result = gftp_parse_ls_mvs (str, fle); | |
1718 break; | |
91 | 1719 default: /* autodetect */ |
1720 if (*lsoutput == '+') | |
1721 result = gftp_parse_ls_eplf (str, fle); | |
1722 else if (isdigit ((int) str[0]) && str[2] == '-') | |
1723 result = gftp_parse_ls_nt (str, fle); | |
1724 else if (str[1] == ' ' && str[2] == '[') | |
1725 result = gftp_parse_ls_novell (str, fle); | |
1726 else | |
107 | 1727 { |
1728 if ((endpos = strchr (str, ' ')) != NULL) | |
1729 { | |
1730 /* If the first token in the string has a ; in it, then */ | |
1731 /* we'll assume that this is a VMS directory listing */ | |
1732 tmpchar = *endpos; | |
1733 *endpos = '\0'; | |
1734 is_vms = strchr (str, ';') != NULL; | |
1735 *endpos = tmpchar; | |
1736 } | |
1737 else | |
1738 is_vms = 0; | |
48 | 1739 |
107 | 1740 if (is_vms) |
485 | 1741 result = gftp_parse_ls_vms (request, fd, str, fle); |
107 | 1742 else |
460 | 1743 result = gftp_parse_ls_unix (request, str, len, fle); |
107 | 1744 } |
91 | 1745 break; |
48 | 1746 } |
1747 g_free (str); | |
1748 | |
1749 if (fle->attribs == NULL) | |
1750 return (result); | |
1751 | |
1752 if (*fle->attribs == 'd') | |
1753 fle->isdir = 1; | |
1754 if (*fle->attribs == 'l') | |
1755 fle->islink = 1; | |
1756 if (strchr (fle->attribs, 'x') != NULL && !fle->isdir && !fle->islink) | |
1757 fle->isexe = 1; | |
1758 | |
1759 return (result); | |
1 | 1760 } |
1761 | |
1762 | |
48 | 1763 static GHashTable * |
469 | 1764 gftp_gen_dir_hash (gftp_request * request, int *ret) |
1 | 1765 { |
48 | 1766 unsigned long *newsize; |
1767 GHashTable * dirhash; | |
1768 gftp_file * fle; | |
1769 char * newname; | |
1770 | |
1771 dirhash = g_hash_table_new (string_hash_function, string_hash_compare); | |
469 | 1772 *ret = gftp_list_files (request); |
1773 if (*ret == 0) | |
48 | 1774 { |
1775 fle = g_malloc0 (sizeof (*fle)); | |
1776 while (gftp_get_next_file (request, NULL, fle) > 0) | |
1777 { | |
1778 newname = fle->file; | |
1779 newsize = g_malloc (sizeof (unsigned long)); | |
1780 *newsize = fle->size; | |
1781 g_hash_table_insert (dirhash, newname, newsize); | |
1782 fle->file = NULL; | |
1783 gftp_file_destroy (fle); | |
1784 } | |
1785 gftp_end_transfer (request); | |
1786 g_free (fle); | |
1787 } | |
1788 else | |
1789 { | |
1790 g_hash_table_destroy (dirhash); | |
1791 dirhash = NULL; | |
1792 } | |
1793 return (dirhash); | |
1794 } | |
39 | 1795 |
48 | 1796 |
1797 static void | |
1798 destroy_hash_ent (gpointer key, gpointer value, gpointer user_data) | |
1799 { | |
39 | 1800 |
48 | 1801 g_free (key); |
1802 g_free (value); | |
1803 } | |
1804 | |
1805 | |
1806 static void | |
1807 gftp_destroy_dir_hash (GHashTable * dirhash) | |
1808 { | |
1809 g_hash_table_foreach (dirhash, destroy_hash_ent, NULL); | |
1810 g_hash_table_destroy (dirhash); | |
1 | 1811 } |
1812 | |
1813 | |
1814 static GList * | |
469 | 1815 gftp_get_dir_listing (gftp_transfer * transfer, int getothdir, int *ret) |
1 | 1816 { |
1817 unsigned long *newsize; | |
1818 GHashTable * dirhash; | |
1819 GList * templist; | |
1820 gftp_file * fle; | |
1821 char *newname; | |
1822 | |
1823 if (getothdir && transfer->toreq) | |
469 | 1824 { |
1825 dirhash = gftp_gen_dir_hash (transfer->toreq, ret); | |
1826 if (*ret < 0) | |
1827 return (NULL); | |
1828 } | |
1 | 1829 else |
1830 dirhash = NULL; | |
1831 | |
1832 if (gftp_list_files (transfer->fromreq) != 0) | |
1833 return (NULL); | |
1834 | |
1835 fle = g_malloc (sizeof (*fle)); | |
1836 templist = NULL; | |
1837 while (gftp_get_next_file (transfer->fromreq, NULL, fle) > 0) | |
1838 { | |
1839 if (strcmp (fle->file, ".") == 0 || strcmp (fle->file, "..") == 0) | |
1840 { | |
1841 gftp_file_destroy (fle); | |
1842 continue; | |
1843 } | |
1844 | |
1845 if (dirhash && | |
1846 (newsize = g_hash_table_lookup (dirhash, fle->file)) != NULL) | |
1847 fle->startsize = *newsize; | |
1848 | |
381 | 1849 if (transfer->toreq && fle->destfile == NULL) |
245 | 1850 fle->destfile = gftp_build_path (transfer->toreq->directory, |
1851 fle->file, NULL); | |
1852 | |
381 | 1853 if (transfer->fromreq->directory != NULL && |
1854 *transfer->fromreq->directory != '\0' && | |
1855 *fle->file != '/') | |
1856 { | |
1857 newname = gftp_build_path (transfer->fromreq->directory, | |
1858 fle->file, NULL); | |
1859 | |
1860 g_free (fle->file); | |
1861 fle->file = newname; | |
1862 } | |
1 | 1863 |
1864 templist = g_list_append (templist, fle); | |
1865 | |
1866 fle = g_malloc (sizeof (*fle)); | |
1867 } | |
1868 gftp_end_transfer (transfer->fromreq); | |
1869 | |
1870 gftp_file_destroy (fle); | |
1871 g_free (fle); | |
1872 | |
1873 if (dirhash) | |
1874 gftp_destroy_dir_hash (dirhash); | |
1875 | |
1876 | |
1877 return (templist); | |
1878 } | |
1879 | |
1880 | |
1881 int | |
1882 gftp_get_all_subdirs (gftp_transfer * transfer, | |
1883 void (*update_func) (gftp_transfer * transfer)) | |
1884 { | |
381 | 1885 char *oldfromdir, *oldtodir, *newname, *pos; |
469 | 1886 int forcecd, remotechanged, ret; |
1 | 1887 GList * templist, * lastlist; |
1888 unsigned long *newsize; | |
1889 GHashTable * dirhash; | |
1890 gftp_file * curfle; | |
1891 | |
84 | 1892 g_return_val_if_fail (transfer != NULL, GFTP_EFATAL); |
1893 g_return_val_if_fail (transfer->fromreq != NULL, GFTP_EFATAL); | |
1894 g_return_val_if_fail (transfer->files != NULL, GFTP_EFATAL); | |
1 | 1895 |
1896 if (transfer->toreq != NULL) | |
469 | 1897 { |
1898 ret = 0; | |
1899 dirhash = gftp_gen_dir_hash (transfer->toreq, &ret); | |
1900 if (ret < 0) | |
1901 return (ret); | |
1902 } | |
1 | 1903 else |
1904 dirhash = NULL; | |
1905 | |
1906 for (lastlist = transfer->files; ; lastlist = lastlist->next) | |
1907 { | |
1908 curfle = lastlist->data; | |
381 | 1909 |
1910 if ((pos = strrchr (curfle->file, '/')) != NULL) | |
1911 pos++; | |
1912 else | |
1913 pos = curfle->file; | |
1914 | |
1915 if (dirhash != NULL && | |
1916 (newsize = g_hash_table_lookup (dirhash, pos)) != NULL) | |
1 | 1917 curfle->startsize = *newsize; |
1918 | |
381 | 1919 if (curfle->size < 0 && GFTP_IS_CONNECTED (transfer->fromreq)) |
1920 curfle->size = gftp_get_file_size (transfer->fromreq, curfle->file); | |
1921 | |
1922 if (transfer->toreq && curfle->destfile == NULL) | |
1923 curfle->destfile = gftp_build_path (transfer->toreq->directory, | |
1924 curfle->file, NULL); | |
1925 | |
1926 if (transfer->fromreq->directory != NULL && | |
1927 *transfer->fromreq->directory != '\0' && | |
1928 *curfle->file != '/') | |
1929 { | |
1930 newname = gftp_build_path (transfer->fromreq->directory, | |
1931 curfle->file, NULL); | |
1932 g_free (curfle->file); | |
1933 curfle->file = newname; | |
1934 } | |
1 | 1935 |
1936 if (lastlist->next == NULL) | |
1937 break; | |
1938 } | |
1939 | |
1940 if (dirhash) | |
1941 gftp_destroy_dir_hash (dirhash); | |
1942 | |
1943 oldfromdir = oldtodir = NULL; | |
1944 remotechanged = 0; | |
1945 forcecd = 0; | |
1946 for (templist = transfer->files; templist != NULL; templist = templist->next) | |
1947 { | |
1948 curfle = templist->data; | |
1949 | |
1950 if (curfle->isdir) | |
1951 { | |
1952 oldfromdir = transfer->fromreq->directory; | |
1953 transfer->fromreq->directory = curfle->file; | |
1954 | |
1955 if (transfer->toreq) | |
1956 { | |
1957 oldtodir = transfer->toreq->directory; | |
1958 transfer->toreq->directory = curfle->destfile; | |
1959 } | |
1960 forcecd = 1; | |
1961 if (gftp_set_directory (transfer->fromreq, | |
1962 transfer->fromreq->directory) == 0) | |
1963 { | |
1964 if (curfle->startsize > 0 && transfer->toreq) | |
1965 { | |
1966 remotechanged = 1; | |
1967 if (gftp_set_directory (transfer->toreq, | |
1968 transfer->toreq->directory) != 0) | |
1969 curfle->startsize = 0; | |
1970 } | |
1971 | |
469 | 1972 ret = 0; |
1 | 1973 lastlist->next = gftp_get_dir_listing (transfer, |
469 | 1974 curfle->startsize > 0, |
1975 &ret); | |
1976 if (ret < 0) | |
1977 { | |
1978 if (!GFTP_IS_CONNECTED (transfer->fromreq) || | |
1979 !GFTP_IS_CONNECTED (transfer->toreq)) | |
1980 return (ret); | |
1981 } | |
1982 | |
1 | 1983 if (lastlist->next != NULL) |
1984 { | |
1985 lastlist->next->prev = lastlist; | |
1986 for (; lastlist->next != NULL; lastlist = lastlist->next); | |
1987 } | |
1988 transfer->numdirs++; | |
1989 if (update_func) | |
1990 update_func (transfer); | |
1991 } | |
1992 else | |
1993 curfle->transfer_action = GFTP_TRANS_ACTION_SKIP; | |
1994 | |
1995 transfer->fromreq->directory = oldfromdir; | |
1996 if (transfer->toreq) | |
1997 transfer->toreq->directory = oldtodir; | |
1998 } | |
1999 else | |
122 | 2000 transfer->numfiles++; |
1 | 2001 } |
2002 | |
2003 if (forcecd) | |
2004 gftp_set_directory (transfer->fromreq, transfer->fromreq->directory); | |
2005 if (remotechanged && transfer->toreq) | |
2006 gftp_set_directory (transfer->toreq, transfer->toreq->directory); | |
2007 | |
2008 if (update_func) | |
2009 { | |
2010 transfer->numfiles = transfer->numdirs = -1; | |
2011 update_func (transfer); | |
2012 } | |
2013 return (0); | |
2014 } | |
2015 | |
2016 | |
2017 #if defined (HAVE_GETADDRINFO) && defined (HAVE_GAI_STRERROR) | |
122 | 2018 static int |
1 | 2019 get_port (struct addrinfo *addr) |
2020 { | |
2021 struct sockaddr_in * saddr; | |
2022 int port; | |
2023 | |
2024 if (addr->ai_family == AF_INET) | |
2025 { | |
2026 saddr = (struct sockaddr_in *) addr->ai_addr; | |
2027 port = ntohs (saddr->sin_port); | |
2028 } | |
2029 else | |
2030 port = 0; | |
2031 | |
2032 return (port); | |
2033 } | |
2034 #endif | |
2035 | |
2036 | |
2037 int | |
122 | 2038 gftp_connect_server (gftp_request * request, char *service, |
2039 char *proxy_hostname, int proxy_port) | |
1 | 2040 { |
2041 char *connect_host, *disphost; | |
2042 int port, sock; | |
2043 #if defined (HAVE_GETADDRINFO) && defined (HAVE_GAI_STRERROR) | |
2044 struct addrinfo hints, *res; | |
463 | 2045 intptr_t enable_ipv6; |
1 | 2046 char serv[8]; |
463 | 2047 int errnum; |
1 | 2048 |
122 | 2049 if ((request->use_proxy = gftp_need_proxy (request, service, |
2050 proxy_hostname, proxy_port)) < 0) | |
84 | 2051 return (request->use_proxy); |
1 | 2052 else if (request->use_proxy == 1) |
2053 request->hostp = NULL; | |
2054 | |
313 | 2055 gftp_lookup_request_option (request, "enable_ipv6", &enable_ipv6); |
2056 | |
151 | 2057 request->free_hostp = 1; |
1 | 2058 memset (&hints, 0, sizeof (hints)); |
2059 hints.ai_flags = AI_CANONNAME; | |
313 | 2060 |
2061 if (enable_ipv6) | |
2062 hints.ai_family = PF_UNSPEC; | |
2063 else | |
2064 hints.ai_family = AF_INET; | |
2065 | |
1 | 2066 hints.ai_socktype = SOCK_STREAM; |
2067 | |
122 | 2068 if (request->use_proxy) |
2069 { | |
2070 connect_host = proxy_hostname; | |
2071 port = proxy_port; | |
2072 } | |
2073 else | |
2074 { | |
2075 connect_host = request->hostname; | |
2076 port = request->port; | |
2077 } | |
1 | 2078 |
2079 if (request->hostp == NULL) | |
2080 { | |
2081 if (port == 0) | |
2082 strcpy (serv, service); | |
2083 else | |
2084 snprintf (serv, sizeof (serv), "%d", port); | |
2085 | |
186 | 2086 request->logging_function (gftp_logging_misc, request, |
168 | 2087 _("Looking up %s\n"), connect_host); |
1 | 2088 if ((errnum = getaddrinfo (connect_host, serv, &hints, |
2089 &request->hostp)) != 0) | |
168 | 2090 { |
186 | 2091 request->logging_function (gftp_logging_error, request, |
168 | 2092 _("Cannot look up hostname %s: %s\n"), |
2093 connect_host, gai_strerror (errnum)); | |
2094 return (GFTP_ERETRYABLE); | |
2095 } | |
1 | 2096 } |
2097 | |
2098 disphost = connect_host; | |
2099 for (res = request->hostp; res != NULL; res = res->ai_next) | |
2100 { | |
2101 disphost = res->ai_canonname ? res->ai_canonname : connect_host; | |
2102 port = get_port (res); | |
56 | 2103 if (!request->use_proxy) |
2104 request->port = port; | |
2105 | |
1 | 2106 if ((sock = socket (res->ai_family, res->ai_socktype, |
2107 res->ai_protocol)) < 0) | |
2108 { | |
186 | 2109 request->logging_function (gftp_logging_error, request, |
1 | 2110 _("Failed to create a socket: %s\n"), |
2111 g_strerror (errno)); | |
2112 continue; | |
66 | 2113 } |
1 | 2114 |
186 | 2115 request->logging_function (gftp_logging_misc, request, |
168 | 2116 _("Trying %s:%d\n"), disphost, port); |
1 | 2117 |
2118 if (connect (sock, res->ai_addr, res->ai_addrlen) == -1) | |
168 | 2119 { |
186 | 2120 request->logging_function (gftp_logging_error, request, |
168 | 2121 _("Cannot connect to %s: %s\n"), |
2122 disphost, g_strerror (errno)); | |
1 | 2123 close (sock); |
2124 continue; | |
168 | 2125 } |
1 | 2126 break; |
2127 } | |
2128 | |
2129 if (res == NULL) | |
2130 { | |
2131 if (request->hostp != NULL) | |
2132 { | |
2133 freeaddrinfo (request->hostp); | |
2134 request->hostp = NULL; | |
2135 } | |
84 | 2136 return (GFTP_ERETRYABLE); |
1 | 2137 } |
2138 | |
2139 #else /* !HAVE_GETADDRINFO */ | |
2140 struct sockaddr_in remote_address; | |
2141 struct servent serv_struct; | |
2142 int curhost; | |
2143 | |
122 | 2144 if ((request->use_proxy = gftp_need_proxy (request, service, |
2145 proxy_hostname, proxy_port)) < 0) | |
84 | 2146 return (request->use_proxy); |
1 | 2147 else if (request->use_proxy == 1) |
2148 request->hostp = NULL; | |
2149 | |
2150 if ((sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) | |
2151 { | |
186 | 2152 request->logging_function (gftp_logging_error, request, |
313 | 2153 _("Failed to create a IPv4 socket: %s\n"), |
1 | 2154 g_strerror (errno)); |
84 | 2155 return (GFTP_ERETRYABLE); |
1 | 2156 } |
2157 | |
2158 memset (&remote_address, 0, sizeof (remote_address)); | |
2159 remote_address.sin_family = AF_INET; | |
2160 | |
122 | 2161 if (request->use_proxy) |
2162 { | |
2163 connect_host = proxy_hostname; | |
2164 port = proxy_port; | |
2165 } | |
2166 else | |
2167 { | |
2168 connect_host = request->hostname; | |
2169 port = request->port; | |
2170 } | |
1 | 2171 |
2172 if (port == 0) | |
2173 { | |
2174 if (!r_getservbyname (service, "tcp", &serv_struct, NULL)) | |
2175 { | |
186 | 2176 request->logging_function (gftp_logging_error, request, |
122 | 2177 _("Cannot look up service name %s/tcp. Please check your services file\n"), |
2178 service); | |
2179 close (sock); | |
2180 return (GFTP_EFATAL); | |
1 | 2181 } |
451 | 2182 |
2183 port = ntohs (serv_struct.s_port); | |
56 | 2184 |
2185 if (!request->use_proxy) | |
451 | 2186 request->port = port; |
1 | 2187 } |
451 | 2188 |
2189 remote_address.sin_port = htons (port); | |
1 | 2190 |
2191 if (request->hostp == NULL) | |
2192 { | |
186 | 2193 request->logging_function (gftp_logging_misc, request, |
168 | 2194 _("Looking up %s\n"), connect_host); |
1 | 2195 if (!(request->hostp = r_gethostbyname (connect_host, &request->host, |
2196 NULL))) | |
2197 { | |
186 | 2198 request->logging_function (gftp_logging_error, request, |
1 | 2199 _("Cannot look up hostname %s: %s\n"), |
2200 connect_host, g_strerror (errno)); | |
2201 close (sock); | |
84 | 2202 return (GFTP_ERETRYABLE); |
1 | 2203 } |
2204 } | |
2205 | |
2206 disphost = NULL; | |
2207 for (curhost = 0; request->host.h_addr_list[curhost] != NULL; curhost++) | |
2208 { | |
2209 disphost = request->host.h_name; | |
2210 memcpy (&remote_address.sin_addr, request->host.h_addr_list[curhost], | |
2211 request->host.h_length); | |
186 | 2212 request->logging_function (gftp_logging_misc, request, |
1 | 2213 _("Trying %s:%d\n"), |
451 | 2214 request->host.h_name, port); |
1 | 2215 |
2216 if (connect (sock, (struct sockaddr *) &remote_address, | |
2217 sizeof (remote_address)) == -1) | |
2218 { | |
186 | 2219 request->logging_function (gftp_logging_error, request, |
1 | 2220 _("Cannot connect to %s: %s\n"), |
2221 connect_host, g_strerror (errno)); | |
2222 } | |
2223 break; | |
2224 } | |
2225 | |
2226 if (request->host.h_addr_list[curhost] == NULL) | |
2227 { | |
2228 close (sock); | |
84 | 2229 return (GFTP_ERETRYABLE); |
1 | 2230 } |
2231 #endif /* HAVE_GETADDRINFO */ | |
2232 | |
182 | 2233 if (fcntl (sock, F_SETFD, 1) == -1) |
2234 { | |
186 | 2235 request->logging_function (gftp_logging_error, request, |
182 | 2236 _("Error: Cannot set close on exec flag: %s\n"), |
2237 g_strerror (errno)); | |
2238 | |
2239 return (GFTP_ERETRYABLE); | |
2240 } | |
2241 | |
186 | 2242 request->logging_function (gftp_logging_misc, request, |
168 | 2243 _("Connected to %s:%d\n"), connect_host, port); |
58 | 2244 |
168 | 2245 if (gftp_fd_set_sockblocking (request, sock, 1) < 0) |
58 | 2246 { |
2247 close (sock); | |
84 | 2248 return (GFTP_ERETRYABLE); |
58 | 2249 } |
2250 | |
169 | 2251 request->datafd = sock; |
168 | 2252 |
2253 if (request->post_connect != NULL) | |
2254 return (request->post_connect (request)); | |
2255 | |
2256 return (0); | |
1 | 2257 } |
2258 | |
2259 | |
177 | 2260 int |
1 | 2261 gftp_set_config_options (gftp_request * request) |
2262 { | |
58 | 2263 if (request->set_config_options != NULL) |
177 | 2264 return (request->set_config_options (request)); |
2265 else | |
2266 return (0); | |
1 | 2267 } |
2268 | |
2269 | |
2270 void | |
2271 print_file_list (GList * list) | |
2272 { | |
2273 gftp_file * tempfle; | |
2274 GList * templist; | |
2275 | |
2276 printf ("--START OF FILE LISTING - TOP TO BOTTOM--\n"); | |
2277 for (templist = list; ; templist = templist->next) | |
2278 { | |
2279 tempfle = templist->data; | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
2280 #if defined (_LARGEFILE_SOURCE) |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
2281 printf ("%s:%s:%lld:%lld:%s:%s:%s\n", |
372 | 2282 tempfle->file, tempfle->destfile, |
2283 (long long) tempfle->size, (long long) tempfle->startsize, | |
2284 tempfle->user, tempfle->group, tempfle->attribs); | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
2285 #else |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
2286 printf ("%s:%s:%ld:%ld:%s:%s:%s\n", |
16 | 2287 tempfle->file, tempfle->destfile, |
2288 tempfle->size, tempfle->startsize, | |
2289 tempfle->user, tempfle->group, tempfle->attribs); | |
372 | 2290 #endif |
1 | 2291 if (templist->next == NULL) |
2292 break; | |
2293 } | |
2294 | |
2295 printf ("--START OF FILE LISTING - BOTTOM TO TOP--\n"); | |
2296 for (; ; templist = templist->prev) | |
2297 { | |
2298 tempfle = templist->data; | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
2299 #if defined (_LARGEFILE_SOURCE) |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
2300 printf ("%s:%s:%lld:%lld:%s:%s:%s\n", |
372 | 2301 tempfle->file, tempfle->destfile, |
2302 (long long) tempfle->size, (long long) tempfle->startsize, | |
2303 tempfle->user, tempfle->group, tempfle->attribs); | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
2304 #else |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
2305 printf ("%s:%s:%ld:%ld:%s:%s:%s\n", |
16 | 2306 tempfle->file, tempfle->destfile, |
2307 tempfle->size, tempfle->startsize, | |
2308 tempfle->user, tempfle->group, tempfle->attribs); | |
372 | 2309 #endif |
1 | 2310 if (templist == list) |
2311 break; | |
2312 } | |
2313 printf ("--END OF FILE LISTING--\n"); | |
2314 } | |
2315 | |
41 | 2316 |
201 | 2317 void |
58 | 2318 gftp_free_getline_buffer (gftp_getline_buffer ** rbuf) |
41 | 2319 { |
58 | 2320 g_free ((*rbuf)->buffer); |
2321 g_free (*rbuf); | |
2322 *rbuf = NULL; | |
41 | 2323 } |
2324 | |
2325 | |
58 | 2326 ssize_t |
2327 gftp_get_line (gftp_request * request, gftp_getline_buffer ** rbuf, | |
2328 char * str, size_t len, int fd) | |
41 | 2329 { |
168 | 2330 ssize_t ret, retval, rlen; |
58 | 2331 char *pos, *nextpos; |
168 | 2332 ssize_t (*read_function) (gftp_request * request, void *ptr, size_t size, |
2333 int fd); | |
179 | 2334 int end_of_buffer; |
168 | 2335 |
2336 if (request == NULL || request->read_function == NULL) | |
2337 read_function = gftp_fd_read; | |
2338 else | |
2339 read_function = request->read_function; | |
58 | 2340 |
2341 if (*rbuf == NULL) | |
2342 { | |
2343 *rbuf = g_malloc0 (sizeof (**rbuf)); | |
2344 (*rbuf)->max_bufsize = len; | |
249 | 2345 (*rbuf)->buffer = g_malloc0 ((*rbuf)->max_bufsize + 1); |
168 | 2346 |
2347 if ((ret = read_function (request, (*rbuf)->buffer, | |
2348 (*rbuf)->max_bufsize, fd)) <= 0) | |
58 | 2349 { |
2350 gftp_free_getline_buffer (rbuf); | |
2351 return (ret); | |
2352 } | |
60 | 2353 (*rbuf)->buffer[ret] = '\0'; |
58 | 2354 (*rbuf)->cur_bufsize = ret; |
2355 (*rbuf)->curpos = (*rbuf)->buffer; | |
2356 } | |
2357 | |
84 | 2358 retval = GFTP_ERETRYABLE; |
58 | 2359 do |
2360 { | |
179 | 2361 pos = strchr ((*rbuf)->curpos, '\n'); |
2362 end_of_buffer = (*rbuf)->curpos == (*rbuf)->buffer && | |
2363 ((*rbuf)->max_bufsize == (*rbuf)->cur_bufsize || (*rbuf)->eof); | |
2364 | |
2365 if ((*rbuf)->cur_bufsize > 0 && (pos != NULL || end_of_buffer)) | |
58 | 2366 { |
2367 if (pos != NULL) | |
2368 { | |
249 | 2369 retval = pos - (*rbuf)->curpos + 1; |
58 | 2370 nextpos = pos + 1; |
2371 if (pos > (*rbuf)->curpos && *(pos - 1) == '\r') | |
2372 pos--; | |
2373 *pos = '\0'; | |
2374 } | |
2375 else | |
249 | 2376 { |
2377 retval = (*rbuf)->cur_bufsize; | |
2378 nextpos = NULL; | |
2379 | |
2380 /* This is not an overflow since we allocated one extra byte to | |
2381 buffer above */ | |
2382 ((*rbuf)->curpos)[retval] = '\0'; | |
2383 } | |
58 | 2384 |
2385 strncpy (str, (*rbuf)->curpos, len); | |
249 | 2386 str[len - 1] = '\0'; |
168 | 2387 (*rbuf)->cur_bufsize -= retval; |
58 | 2388 |
168 | 2389 if (nextpos != NULL) |
2390 (*rbuf)->curpos = nextpos; | |
2391 else | |
2392 (*rbuf)->cur_bufsize = 0; | |
58 | 2393 break; |
2394 } | |
2395 else | |
2396 { | |
2397 if ((*rbuf)->cur_bufsize == 0 || *(*rbuf)->curpos == '\0') | |
2398 { | |
2399 rlen = (*rbuf)->max_bufsize; | |
2400 pos = (*rbuf)->buffer; | |
2401 } | |
2402 else | |
2403 { | |
168 | 2404 memmove ((*rbuf)->buffer, (*rbuf)->curpos, (*rbuf)->cur_bufsize); |
2405 pos = (*rbuf)->buffer + (*rbuf)->cur_bufsize; | |
2406 rlen = (*rbuf)->max_bufsize - (*rbuf)->cur_bufsize; | |
58 | 2407 } |
168 | 2408 |
58 | 2409 (*rbuf)->curpos = (*rbuf)->buffer; |
2410 | |
209 | 2411 if ((*rbuf)->eof) |
2412 ret = 0; | |
2413 else | |
2414 ret = read_function (request, pos, rlen, fd); | |
2415 | |
2416 if (ret < 0) | |
58 | 2417 { |
2418 gftp_free_getline_buffer (rbuf); | |
2419 return (ret); | |
2420 } | |
179 | 2421 else if (ret == 0) |
168 | 2422 { |
179 | 2423 if ((*rbuf)->cur_bufsize == 0) |
2424 { | |
2425 gftp_free_getline_buffer (rbuf); | |
2426 return (ret); | |
2427 } | |
2428 | |
2429 (*rbuf)->eof = 1; | |
168 | 2430 } |
2431 | |
2432 (*rbuf)->cur_bufsize += ret; | |
215 | 2433 (*rbuf)->curpos[(*rbuf)->cur_bufsize] = '\0'; |
58 | 2434 } |
2435 } | |
84 | 2436 while (retval == GFTP_ERETRYABLE); |
58 | 2437 |
2438 return (retval); | |
2439 } | |
2440 | |
2441 | |
2442 ssize_t | |
168 | 2443 gftp_fd_read (gftp_request * request, void *ptr, size_t size, int fd) |
58 | 2444 { |
325 | 2445 intptr_t network_timeout; |
58 | 2446 struct timeval tv; |
2447 fd_set fset; | |
2448 ssize_t ret; | |
41 | 2449 |
122 | 2450 gftp_lookup_request_option (request, "network_timeout", &network_timeout); |
2451 | |
41 | 2452 errno = 0; |
2453 ret = 0; | |
2454 do | |
2455 { | |
58 | 2456 FD_ZERO (&fset); |
2457 FD_SET (fd, &fset); | |
122 | 2458 tv.tv_sec = network_timeout; |
58 | 2459 tv.tv_usec = 0; |
2460 ret = select (fd + 1, &fset, NULL, NULL, &tv); | |
2461 if (ret == -1 && errno == EINTR) | |
41 | 2462 { |
58 | 2463 if (request && request->cancel) |
2464 break; | |
2465 else | |
2466 continue; | |
2467 } | |
2468 else if (ret <= 0) | |
2469 { | |
2470 if (request != NULL) | |
41 | 2471 { |
186 | 2472 request->logging_function (gftp_logging_error, request, |
58 | 2473 _("Connection to %s timed out\n"), |
2474 request->hostname); | |
2475 gftp_disconnect (request); | |
2476 } | |
84 | 2477 return (GFTP_ERETRYABLE); |
41 | 2478 } |
2479 | |
58 | 2480 if ((ret = read (fd, ptr, size)) < 0) |
41 | 2481 { |
2482 if (errno == EINTR) | |
2483 { | |
58 | 2484 if (request != NULL && request->cancel) |
41 | 2485 break; |
2486 else | |
58 | 2487 continue; |
41 | 2488 } |
2489 | |
58 | 2490 if (request != NULL) |
2491 { | |
186 | 2492 request->logging_function (gftp_logging_error, request, |
58 | 2493 _("Error: Could not read from socket: %s\n"), |
41 | 2494 g_strerror (errno)); |
58 | 2495 gftp_disconnect (request); |
2496 } | |
84 | 2497 return (GFTP_ERETRYABLE); |
41 | 2498 } |
2499 } | |
58 | 2500 while (errno == EINTR && !(request != NULL && request->cancel)); |
41 | 2501 |
58 | 2502 if (errno == EINTR && request != NULL && request->cancel) |
41 | 2503 { |
2504 gftp_disconnect (request); | |
84 | 2505 return (GFTP_ERETRYABLE); |
41 | 2506 } |
2507 | |
2508 return (ret); | |
2509 } | |
2510 | |
58 | 2511 |
2512 ssize_t | |
168 | 2513 gftp_fd_write (gftp_request * request, const char *ptr, size_t size, int fd) |
58 | 2514 { |
325 | 2515 intptr_t network_timeout; |
58 | 2516 struct timeval tv; |
248 | 2517 ssize_t w_ret; |
58 | 2518 fd_set fset; |
248 | 2519 size_t ret; |
58 | 2520 |
122 | 2521 gftp_lookup_request_option (request, "network_timeout", &network_timeout); |
2522 | |
58 | 2523 errno = 0; |
2524 ret = 0; | |
2525 do | |
2526 { | |
2527 FD_ZERO (&fset); | |
2528 FD_SET (fd, &fset); | |
122 | 2529 tv.tv_sec = network_timeout; |
58 | 2530 tv.tv_usec = 0; |
2531 ret = select (fd + 1, NULL, &fset, NULL, &tv); | |
2532 if (ret == -1 && errno == EINTR) | |
2533 { | |
2534 if (request != NULL && request->cancel) | |
2535 break; | |
2536 else | |
2537 continue; | |
2538 } | |
2539 else if (ret <= 0) | |
2540 { | |
2541 if (request != NULL) | |
2542 { | |
186 | 2543 request->logging_function (gftp_logging_error, request, |
58 | 2544 _("Connection to %s timed out\n"), |
2545 request->hostname); | |
2546 gftp_disconnect (request); | |
2547 } | |
84 | 2548 return (GFTP_ERETRYABLE); |
58 | 2549 } |
2550 | |
248 | 2551 w_ret = write (fd, ptr, size); |
2552 if (w_ret < 0) | |
58 | 2553 { |
2554 if (errno == EINTR) | |
2555 { | |
2556 if (request != NULL && request->cancel) | |
2557 break; | |
2558 else | |
2559 continue; | |
2560 } | |
2561 | |
2562 if (request != NULL) | |
2563 { | |
186 | 2564 request->logging_function (gftp_logging_error, request, |
58 | 2565 _("Error: Could not write to socket: %s\n"), |
2566 g_strerror (errno)); | |
2567 gftp_disconnect (request); | |
2568 } | |
84 | 2569 return (GFTP_ERETRYABLE); |
58 | 2570 } |
2571 | |
2572 ptr += w_ret; | |
2573 size -= w_ret; | |
2574 ret += w_ret; | |
2575 } | |
2576 while (size > 0); | |
2577 | |
2578 if (errno == EINTR && request != NULL && request->cancel) | |
2579 { | |
2580 gftp_disconnect (request); | |
84 | 2581 return (GFTP_ERETRYABLE); |
58 | 2582 } |
2583 | |
2584 return (ret); | |
2585 } | |
2586 | |
2587 | |
2588 ssize_t | |
2589 gftp_writefmt (gftp_request * request, int fd, const char *fmt, ...) | |
2590 { | |
2591 char *tempstr; | |
2592 va_list argp; | |
2593 ssize_t ret; | |
2594 | |
2595 va_start (argp, fmt); | |
2596 tempstr = g_strdup_vprintf (fmt, argp); | |
2597 va_end (argp); | |
2598 | |
168 | 2599 ret = request->write_function (request, tempstr, strlen (tempstr), fd); |
58 | 2600 g_free (tempstr); |
2601 return (ret); | |
2602 } | |
2603 | |
2604 | |
2605 int | |
168 | 2606 gftp_fd_set_sockblocking (gftp_request * request, int fd, int non_blocking) |
58 | 2607 { |
2608 int flags; | |
2609 | |
84 | 2610 if ((flags = fcntl (fd, F_GETFL, 0)) < 0) |
58 | 2611 { |
186 | 2612 request->logging_function (gftp_logging_error, request, |
58 | 2613 _("Cannot get socket flags: %s\n"), |
2614 g_strerror (errno)); | |
2615 gftp_disconnect (request); | |
84 | 2616 return (GFTP_ERETRYABLE); |
58 | 2617 } |
2618 | |
2619 if (non_blocking) | |
2620 flags |= O_NONBLOCK; | |
2621 else | |
2622 flags &= ~O_NONBLOCK; | |
2623 | |
84 | 2624 if (fcntl (fd, F_SETFL, flags) < 0) |
58 | 2625 { |
186 | 2626 request->logging_function (gftp_logging_error, request, |
58 | 2627 _("Cannot set socket to non-blocking: %s\n"), |
2628 g_strerror (errno)); | |
2629 gftp_disconnect (request); | |
84 | 2630 return (GFTP_ERETRYABLE); |
58 | 2631 } |
2632 | |
2633 return (0); | |
2634 } | |
2635 | |
2636 | |
63 | 2637 void |
2638 gftp_swap_socks (gftp_request * dest, gftp_request * source) | |
2639 { | |
2640 g_return_if_fail (dest != NULL); | |
2641 g_return_if_fail (source != NULL); | |
2642 g_return_if_fail (dest->protonum == source->protonum); | |
2643 | |
2644 dest->datafd = source->datafd; | |
2645 dest->cached = 0; | |
397 | 2646 #ifdef USE_SSL |
2647 dest->ssl = source->ssl; | |
2648 #endif | |
2649 | |
63 | 2650 if (!source->always_connected) |
2651 { | |
2652 source->datafd = -1; | |
2653 source->cached = 1; | |
397 | 2654 #ifdef USE_SSL |
2655 source->ssl = NULL; | |
2656 #endif | |
63 | 2657 } |
2658 | |
2659 if (dest->swap_socks) | |
2660 dest->swap_socks (dest, source); | |
2661 } | |
2662 | |
122 | 2663 |
2664 void | |
2665 gftp_calc_kbs (gftp_transfer * tdata, ssize_t num_read) | |
2666 { | |
469 | 2667 /* Needed for systems that size(float) < size(void *) */ |
2668 union { intptr_t i; float f; } maxkbs; | |
122 | 2669 unsigned long waitusecs; |
220 | 2670 double start_difftime; |
122 | 2671 gftp_file * tempfle; |
2672 struct timeval tv; | |
222 | 2673 int waited; |
122 | 2674 |
469 | 2675 gftp_lookup_request_option (tdata->fromreq, "maxkbs", &maxkbs.f); |
122 | 2676 |
2677 if (g_thread_supported ()) | |
2678 g_static_mutex_lock (&tdata->statmutex); | |
2679 | |
220 | 2680 gettimeofday (&tv, NULL); |
2681 | |
122 | 2682 tempfle = tdata->curfle->data; |
2683 tdata->trans_bytes += num_read; | |
2684 tdata->curtrans += num_read; | |
2685 tdata->stalled = 0; | |
2686 | |
220 | 2687 start_difftime = (tv.tv_sec - tdata->starttime.tv_sec) + ((double) (tv.tv_usec - tdata->starttime.tv_usec) / 1000000.0); |
2688 | |
2689 if (start_difftime <= 0) | |
2690 tdata->kbs = tdata->trans_bytes / 1024.0; | |
122 | 2691 else |
220 | 2692 tdata->kbs = tdata->trans_bytes / 1024.0 / start_difftime; |
2693 | |
222 | 2694 waited = 0; |
469 | 2695 if (maxkbs.f > 0 && tdata->kbs > maxkbs.f) |
122 | 2696 { |
469 | 2697 waitusecs = num_read / 1024.0 / maxkbs.f * 1000000.0 - start_difftime; |
122 | 2698 |
2699 if (waitusecs > 0) | |
2700 { | |
2701 if (g_thread_supported ()) | |
2702 g_static_mutex_unlock (&tdata->statmutex); | |
2703 | |
222 | 2704 waited = 1; |
122 | 2705 usleep (waitusecs); |
2706 | |
2707 if (g_thread_supported ()) | |
2708 g_static_mutex_lock (&tdata->statmutex); | |
2709 } | |
222 | 2710 |
122 | 2711 } |
2712 | |
222 | 2713 if (waited) |
2714 gettimeofday (&tdata->lasttime, NULL); | |
2715 else | |
2716 memcpy (&tdata->lasttime, &tv, sizeof (tdata->lasttime)); | |
122 | 2717 |
2718 if (g_thread_supported ()) | |
2719 g_static_mutex_unlock (&tdata->statmutex); | |
2720 } | |
2721 | |
125 | 2722 |
2723 int | |
2724 gftp_get_transfer_status (gftp_transfer * tdata, ssize_t num_read) | |
2725 { | |
325 | 2726 int ret1, ret2; |
2727 intptr_t retries, sleep_time; | |
125 | 2728 gftp_file * tempfle; |
2729 struct timeval tv; | |
2730 | |
2731 ret1 = ret2 = 0; | |
2732 gftp_lookup_request_option (tdata->fromreq, "retries", &retries); | |
2733 gftp_lookup_request_option (tdata->fromreq, "sleep_time", &sleep_time); | |
2734 | |
2735 if (g_thread_supported ()) | |
2736 g_static_mutex_lock (&tdata->structmutex); | |
2737 | |
2738 if (tdata->curfle == NULL) | |
2739 { | |
2740 if (g_thread_supported ()) | |
2741 g_static_mutex_unlock (&tdata->structmutex); | |
2742 | |
2743 return (GFTP_EFATAL); | |
2744 } | |
2745 | |
2746 tempfle = tdata->curfle->data; | |
2747 | |
2748 if (g_thread_supported ()) | |
2749 g_static_mutex_unlock (&tdata->structmutex); | |
2750 | |
2751 gftp_disconnect (tdata->fromreq); | |
2752 gftp_disconnect (tdata->toreq); | |
2753 | |
2754 if (num_read < 0 || tdata->skip_file) | |
2755 { | |
2756 if (num_read == GFTP_EFATAL) | |
2757 return (GFTP_EFATAL); | |
303 | 2758 else if (!tdata->conn_error_no_timeout) |
125 | 2759 { |
303 | 2760 if (retries != 0 && |
2761 tdata->current_file_retries >= retries) | |
2762 { | |
2763 tdata->fromreq->logging_function (gftp_logging_error, tdata->fromreq, | |
2764 _("Error: Remote site %s disconnected. Max retries reached...giving up\n"), | |
2765 tdata->fromreq->hostname != NULL ? | |
2766 tdata->fromreq->hostname : tdata->toreq->hostname); | |
2767 return (GFTP_EFATAL); | |
2768 } | |
2769 else | |
2770 { | |
2771 tdata->fromreq->logging_function (gftp_logging_error, tdata->fromreq, | |
2772 _("Error: Remote site %s disconnected. Will reconnect in %d seconds\n"), | |
2773 tdata->fromreq->hostname != NULL ? | |
2774 tdata->fromreq->hostname : tdata->toreq->hostname, | |
2775 sleep_time); | |
2776 } | |
125 | 2777 } |
2778 | |
2779 while (retries == 0 || | |
2780 tdata->current_file_retries <= retries) | |
2781 { | |
303 | 2782 if (!tdata->conn_error_no_timeout && !tdata->skip_file) |
125 | 2783 { |
2784 tv.tv_sec = sleep_time; | |
2785 tv.tv_usec = 0; | |
2786 select (0, NULL, NULL, NULL, &tv); | |
2787 } | |
303 | 2788 else |
2789 tdata->conn_error_no_timeout = 0; | |
125 | 2790 |
2791 if ((ret1 = gftp_connect (tdata->fromreq)) == 0 && | |
2792 (ret2 = gftp_connect (tdata->toreq)) == 0) | |
2793 { | |
2794 if (g_thread_supported ()) | |
2795 g_static_mutex_lock (&tdata->structmutex); | |
2796 | |
2797 tdata->resumed_bytes = tdata->resumed_bytes + tdata->trans_bytes - tdata->curresumed - tdata->curtrans; | |
2798 tdata->trans_bytes = 0; | |
2799 if (tdata->skip_file) | |
2800 { | |
2801 tdata->total_bytes -= tempfle->size; | |
2802 tdata->curtrans = 0; | |
2803 | |
2804 tdata->curfle = tdata->curfle->next; | |
2805 tdata->next_file = 1; | |
2806 tdata->skip_file = 0; | |
2807 tdata->cancel = 0; | |
2808 tdata->fromreq->cancel = 0; | |
2809 tdata->toreq->cancel = 0; | |
2810 } | |
2811 else | |
2812 { | |
2813 tempfle->transfer_action = GFTP_TRANS_ACTION_RESUME; | |
2814 tempfle->startsize = tdata->curtrans + tdata->curresumed; | |
2815 /* We decrement this here because it will be incremented in | |
2816 the loop again */ | |
2817 tdata->curresumed = 0; | |
2818 tdata->current_file_number--; /* Decrement this because it | |
2819 will be incremented when we | |
2820 continue in the loop */ | |
2821 } | |
2822 | |
2823 gettimeofday (&tdata->starttime, NULL); | |
2824 | |
2825 if (g_thread_supported ()) | |
2826 g_static_mutex_unlock (&tdata->structmutex); | |
2827 | |
2828 return (GFTP_ERETRYABLE); | |
2829 } | |
2830 else if (ret1 == GFTP_EFATAL || ret2 == GFTP_EFATAL) | |
2831 { | |
2832 gftp_disconnect (tdata->fromreq); | |
2833 gftp_disconnect (tdata->toreq); | |
2834 return (GFTP_EFATAL); | |
2835 } | |
2836 else | |
2837 tdata->current_file_retries++; | |
2838 } | |
2839 } | |
2840 else if (tdata->cancel) | |
2841 return (GFTP_EFATAL); | |
2842 | |
2843 return (0); | |
2844 } | |
2845 | |
182 | 2846 |
2847 int | |
2848 gftp_fd_open (gftp_request * request, const char *pathname, int flags, mode_t mode) | |
2849 { | |
2850 int fd; | |
2851 | |
227 | 2852 if (mode == 0) |
2853 fd = open (pathname, flags); | |
2854 else | |
2855 fd = open (pathname, flags, mode); | |
2856 | |
2857 if (fd < 0) | |
182 | 2858 { |
2859 if (request != NULL) | |
186 | 2860 request->logging_function (gftp_logging_error, request, |
182 | 2861 _("Error: Cannot open local file %s: %s\n"), |
2862 pathname, g_strerror (errno)); | |
2863 return (GFTP_ERETRYABLE); | |
2864 } | |
2865 | |
2866 if (fcntl (fd, F_SETFD, 1) == -1) | |
2867 { | |
2868 if (request != NULL) | |
186 | 2869 request->logging_function (gftp_logging_error, request, |
182 | 2870 _("Error: Cannot set close on exec flag: %s\n"), |
2871 g_strerror (errno)); | |
2872 | |
2873 return (-1); | |
2874 } | |
2875 | |
2876 return (fd); | |
2877 } | |
422 | 2878 |
2879 | |
2880 void | |
2881 gftp_setup_startup_directory (gftp_request * request) | |
2882 { | |
2883 char *startup_directory, *tempstr; | |
2884 | |
2885 gftp_lookup_request_option (request, "startup_directory", &startup_directory); | |
2886 | |
2887 if (*startup_directory != '\0' && | |
2888 (tempstr = expand_path (startup_directory)) != NULL) | |
2889 { | |
2890 gftp_set_directory (request, tempstr); | |
2891 g_free (tempstr); | |
2892 } | |
2893 } | |
2894 |