ReactOS 0.4.15-dev-6694-g4ba8af9
io.c
Go to the documentation of this file.
1/* io.c
2 *
3 * Copyright (c) 1996-2001 Mike Gleason, NCEMRSoft.
4 * All rights reserved.
5 *
6 */
7
8#include "syshdrs.h"
9
10static int gGotBrokenData = 0;
11
12#if defined(WIN32) || defined(_WINDOWS)
13# define ASCII_TRANSLATION 0
14#endif
15
16#ifndef ASCII_TRANSLATION
17# define ASCII_TRANSLATION 1
18#endif
19
20#if !defined(NO_SIGNALS) && (USE_SIO || !defined(SIGALRM) || !defined(SIGPIPE) || !defined(SIGINT))
21# define NO_SIGNALS 1
22#endif
23
24#ifndef NO_SIGNALS
25
26#ifdef HAVE_SIGSETJMP
27static sigjmp_buf gBrokenDataJmp;
28#else
29static jmp_buf gBrokenDataJmp;
30#endif /* HAVE_SIGSETJMP */
31static int gCanBrokenDataJmp = 0;
32
33#endif /* NO_SIGNALS */
34
35
36#ifndef O_BINARY
37 /* Needed for platforms using different EOLN sequence (i.e. DOS) */
38# ifdef _O_BINARY
39# define O_BINARY _O_BINARY
40# else
41# define O_BINARY 0
42# endif
43#endif
44
45static int WaitForRemoteInput(const FTPCIPtr cip);
46static int WaitForRemoteOutput(const FTPCIPtr cip);
47
48
49#ifndef NO_SIGNALS
50
51static void
52BrokenData(int signum)
53{
54 gGotBrokenData = signum;
55 if (gCanBrokenDataJmp != 0) {
56 gCanBrokenDataJmp = 0;
57#ifdef HAVE_SIGSETJMP
58 siglongjmp(gBrokenDataJmp, 1);
59#else
60 longjmp(gBrokenDataJmp, 1);
61#endif /* HAVE_SIGSETJMP */
62 }
63} /* BrokenData */
64
65#endif /* NO_SIGNALS */
66
67
68
69
70void
72{
75 cip->mdtm = kModTimeUnknown;
76 cip->rname = NULL;
77 cip->lname = NULL;
78 cip->kBytesPerSec = -1.0;
79 cip->percentCompleted = -1.0;
80 cip->sec = -1.0;
81 cip->secLeft = -1.0;
82 cip->nextProgressUpdate = 0;
83 cip->stalled = 0;
84 cip->dataTimedOut = 0;
85 cip->useProgressMeter = 1;
86 (void) gettimeofday(&cip->t0, NULL);
87} /* FTPInitIOTimer */
88
89
90
91
92void
94{
95 (void) gettimeofday(&cip->t0, NULL);
96 if (cip->progress != (FTPProgressMeterProc) 0)
97 (*cip->progress)(cip, kPrInitMsg);
98} /* FTPStartIOTimer */
99
100
101
102
103void
105{
106 double sec;
107 struct timeval *t0, t1;
108 time_t now;
109
110 (void) time(&now);
111 if (now < cip->nextProgressUpdate)
112 return;
113 now += 1;
114 cip->nextProgressUpdate = now;
115
116 (void) gettimeofday(&t1, NULL);
117 t0 = &cip->t0;
118
119 if (t0->tv_usec > t1.tv_usec) {
120 t1.tv_usec += 1000000;
121 t1.tv_sec--;
122 }
123 sec = ((double) (t1.tv_usec - t0->tv_usec) * 0.000001)
124 + (t1.tv_sec - t0->tv_sec);
125 if (sec > 0.0) {
126 cip->kBytesPerSec = ((double) cip->bytesTransferred) / (1024.0 * sec);
127 } else {
128 cip->kBytesPerSec = -1.0;
129 }
130 if (cip->expectedSize == kSizeUnknown) {
131 cip->percentCompleted = -1.0;
132 cip->secLeft = -1.0;
133 } else if (cip->expectedSize <= 0) {
134 cip->percentCompleted = 100.0;
135 cip->secLeft = 0.0;
136 } else {
137 cip->percentCompleted = ((double) (100.0 * (cip->bytesTransferred + cip->startPoint))) / ((double) cip->expectedSize);
138 if (cip->percentCompleted >= 100.0) {
139 cip->percentCompleted = 100.0;
140 cip->secLeft = 0.0;
141 } else if (cip->percentCompleted <= 0.0) {
142 cip->secLeft = 999.0;
143 }
144 if (cip->kBytesPerSec > 0.0) {
145 cip->secLeft = ((cip->expectedSize - cip->bytesTransferred - cip->startPoint) / 1024.0) / cip->kBytesPerSec;
146 if (cip->secLeft < 0.0)
147 cip->secLeft = 0.0;
148 }
149 }
150 cip->sec = sec;
151 if ((cip->progress != (FTPProgressMeterProc) 0) && (cip->useProgressMeter != 0))
152 (*cip->progress)(cip, kPrUpdateMsg);
153} /* FTPUpdateIOTimer */
154
155
156
157
158void
160{
161 cip->nextProgressUpdate = 0; /* force last update */
162 FTPUpdateIOTimer(cip);
163 if (cip->progress != (FTPProgressMeterProc) 0)
164 (*cip->progress)(cip, kPrEndMsg);
165} /* FTPStopIOTimer */
166
167
168
169
170/* This isn't too useful -- it mostly serves as an example so you can write
171 * your own function to do what you need to do with the listing.
172 */
173int
174FTPList(const FTPCIPtr cip, const int outfd, const int longMode, const char *const lsflag)
175{
176 const char *cmd;
177 char line[512];
178 char secondaryBuf[768];
179#ifndef NO_SIGNALS
180 char *secBufPtr, *secBufLimit;
181 int nread;
182 volatile int result;
183#else /* NO_SIGNALS */
184 SReadlineInfo lsSrl;
185 int result;
186#endif /* NO_SIGNALS */
187
188 if (cip == NULL)
189 return (kErrBadParameter);
190 if (strcmp(cip->magic, kLibraryMagic))
191 return (kErrBadMagic);
192
193 cmd = (longMode != 0) ? "LIST" : "NLST";
194 if ((lsflag == NULL) || (lsflag[0] == '\0')) {
196 } else {
197 result = FTPStartDataCmd(cip, kNetReading, kTypeAscii, (longest_int) 0, "%s %s", cmd, lsflag);
198 }
199
200
201#ifdef NO_SIGNALS
202
203 if (result == 0) {
204 if (InitSReadlineInfo(&lsSrl, cip->dataSocket, secondaryBuf, sizeof(secondaryBuf), (int) cip->xferTimeout, 1) < 0) {
205 /* Not really fdopen, but close in what we're trying to do. */
207 cip->errNo = kErrFdopenR;
208 Error(cip, kDoPerror, "Could not fdopen.\n");
209 return (result);
210 }
211
212 for (;;) {
213 result = SReadline(&lsSrl, line, sizeof(line) - 2);
214 if (result == kTimeoutErr) {
215 /* timeout */
216 Error(cip, kDontPerror, "Could not directory listing data -- timed out.\n");
217 cip->errNo = kErrDataTimedOut;
218 return (cip->errNo);
219 } else if (result == 0) {
220 /* end of listing -- done */
221 cip->numListings++;
222 break;
223 } else if (result < 0) {
224 /* error */
225 Error(cip, kDoPerror, "Could not read directory listing data");
227 cip->errNo = kErrLISTFailed;
228 break;
229 }
230
231 (void) write(outfd, line, strlen(line));
232 }
233
234 DisposeSReadlineInfo(&lsSrl);
235 if (FTPEndDataCmd(cip, 1) < 0) {
237 cip->errNo = kErrLISTFailed;
238 }
239 } else if (result == kErrGeneric) {
241 cip->errNo = kErrLISTFailed;
242 }
243
244
245#else /* NO_SIGNALS */
246
247 if (result == 0) {
248 /* This line sets the buffer pointer so that the first thing
249 * BufferGets will do is reset and fill the buffer using
250 * real I/O.
251 */
252 secBufPtr = secondaryBuf + sizeof(secondaryBuf);
253 secBufLimit = (char *) 0;
254
255 for (;;) {
256 if (cip->xferTimeout > 0)
257 (void) alarm(cip->xferTimeout);
258 nread = BufferGets(line, sizeof(line), cip->dataSocket, secondaryBuf, &secBufPtr, &secBufLimit, sizeof(secondaryBuf));
259 if (nread <= 0) {
260 if (nread < 0)
261 break;
262 } else {
263 cip->bytesTransferred += (longest_int) nread;
264 (void) STRNCAT(line, "\n");
265 (void) write(outfd, line, strlen(line));
266 }
267 }
268 if (cip->xferTimeout > 0)
269 (void) alarm(0);
270 result = FTPEndDataCmd(cip, 1);
271 if (result < 0) {
273 cip->errNo = kErrLISTFailed;
274 }
275 result = kNoErr;
276 cip->numListings++;
277 } else if (result == kErrGeneric) {
279 cip->errNo = kErrLISTFailed;
280 }
281#endif /* NO_SIGNALS */
282 return (result);
283} /* FTPList */
284
285
286
287
288static void
290{
291 int f;
292 char optstr[128];
293 size_t optstrlen;
294
295 if (cip->usedMLS == 0) {
296 /* First MLSD/MLST ? */
297 cip->usedMLS = 1;
298
300 optstr[0] = '\0';
301
302 /* TYPE */
303 if ((f & kMlsOptType) != 0) {
304 STRNCAT(optstr, "type;");
305 }
306
307 /* SIZE */
308 if ((f & kMlsOptSize) != 0) {
309 STRNCAT(optstr, "size;");
310 }
311
312 /* MODTIME */
313 if ((f & kMlsOptModify) != 0) {
314 STRNCAT(optstr, "modify;");
315 }
316
317 /* MODE */
318 if ((f & kMlsOptUNIXmode) != 0) {
319 STRNCAT(optstr, "UNIX.mode;");
320 }
321
322 /* PERM */
323 if ((f & kMlsOptPerm) != 0) {
324 STRNCAT(optstr, "perm;");
325 }
326
327 /* OWNER */
328 if ((f & kMlsOptUNIXowner) != 0) {
329 STRNCAT(optstr, "UNIX.owner;");
330 }
331
332 /* UID */
333 if ((f & kMlsOptUNIXuid) != 0) {
334 STRNCAT(optstr, "UNIX.uid;");
335 }
336
337 /* GROUP */
338 if ((f & kMlsOptUNIXgroup) != 0) {
339 STRNCAT(optstr, "UNIX.group;");
340 }
341
342 /* GID */
343 if ((f & kMlsOptUNIXgid) != 0) {
344 STRNCAT(optstr, "UNIX.gid;");
345 }
346
347 /* UNIQUE */
348 if ((f & kMlsOptUnique) != 0) {
349 STRNCAT(optstr, "unique;");
350 }
351
352 /* Tell the server what we prefer. */
353 optstrlen = strlen(optstr);
354 if (optstrlen > 0) {
355 if (optstr[optstrlen - 1] == ';')
356 optstr[optstrlen - 1] = '\0';
357 (void) FTPCmd(cip, "OPTS MLST %s", optstr);
358 }
359 }
360} /* FTPRequestMlsOptions */
361
362
363
364
365int
366FTPListToMemory2(const FTPCIPtr cip, const char *const pattern, const LineListPtr llines, const char *const lsflags, const int blankLines, int *const tryMLSD)
367{
368 char secondaryBuf[768];
369 char line[512];
370 char lsflags1[128];
371 const char *command = "NLST";
372 const char *scp;
373 char *dcp, *lim;
374#ifndef NO_SIGNALS
375 char *secBufPtr, *secBufLimit;
376 volatile FTPSigProc osigpipe;
377 volatile FTPCIPtr vcip;
378 int sj;
379 int nread;
380 volatile int result;
381#else /* NO_SIGNALS */
382 SReadlineInfo lsSrl;
383 int result;
384#endif /* NO_SIGNALS */
385
386 if (cip == NULL)
387 return (kErrBadParameter);
388 if (strcmp(cip->magic, kLibraryMagic))
389 return (kErrBadMagic);
390
391 if ((llines == NULL) || (pattern == NULL) || (lsflags == NULL))
392 return (kErrBadParameter);
393
394 if ((tryMLSD != (int *) 0) && (*tryMLSD != 0) && (cip->hasMLSD == kCommandAvailable)) {
395 command = "MLSD";
396 if ((lsflags[0] == '-') && (strchr(lsflags, 'd') != NULL) && (cip->hasMLST == kCommandAvailable))
397 command = "MLST";
398 lsflags1[0] = '\0';
400 } else {
401 /* Not using MLSD. */
402 if (tryMLSD != (int *) 0)
403 *tryMLSD = 0;
404 if (lsflags[0] == '-') {
405 /* See if we should use LIST instead. */
406 scp = lsflags + 1;
407 dcp = lsflags1;
408 lim = lsflags1 + sizeof(lsflags1) - 2;
409 for (; *scp != '\0'; scp++) {
410 if (*scp == 'l') {
411 /* do not add the 'l' */
412 command = "LIST";
413 } else if (dcp < lim) {
414 if (dcp == lsflags1)
415 *dcp++ = '-';
416 *dcp++ = *scp;
417 }
418 }
419 *dcp = '\0';
420 } else {
421 (void) STRNCPY(lsflags1, lsflags);
422 }
423 }
424
425 InitLineList(llines);
426
428 cip,
431 (longest_int) 0,
432 "%s%s%s%s%s",
433 command,
434 (lsflags1[0] == '\0') ? "" : " ",
435 lsflags1,
436 (pattern[0] == '\0') ? "" : " ",
437 pattern
438 );
439
440#ifdef NO_SIGNALS
441
442 if (result == 0) {
443 if (InitSReadlineInfo(&lsSrl, cip->dataSocket, secondaryBuf, sizeof(secondaryBuf), (int) cip->xferTimeout, 1) < 0) {
444 /* Not really fdopen, but close in what we're trying to do. */
446 cip->errNo = kErrFdopenR;
447 Error(cip, kDoPerror, "Could not fdopen.\n");
448 return (result);
449 }
450
451 for (;;) {
452 result = SReadline(&lsSrl, line, sizeof(line) - 1);
453 if (result == kTimeoutErr) {
454 /* timeout */
455 Error(cip, kDontPerror, "Could not directory listing data -- timed out.\n");
456 cip->errNo = kErrDataTimedOut;
457 return (cip->errNo);
458 } else if (result == 0) {
459 /* end of listing -- done */
460 cip->numListings++;
461 break;
462 } else if (result < 0) {
463 /* error */
464 Error(cip, kDoPerror, "Could not read directory listing data");
466 cip->errNo = kErrLISTFailed;
467 break;
468 }
469
470 if (line[result - 1] == '\n')
471 line[result - 1] = '\0';
472
473 if ((blankLines == 0) && (result <= 1))
474 continue;
475
476 /* Valid directory listing line of output */
477 if ((line[0] == '.') && ((line[1] == '\0') || ((line[1] == '.') && ((line[2] == '\0') || (iscntrl(line[2]))))))
478 continue; /* Skip . and .. */
479
480 (void) AddLine(llines, line);
481 }
482
483 DisposeSReadlineInfo(&lsSrl);
484 if (FTPEndDataCmd(cip, 1) < 0) {
486 cip->errNo = kErrLISTFailed;
487 }
488 } else if (result == kErrGeneric) {
490 cip->errNo = kErrLISTFailed;
491 }
492
493
494#else /* NO_SIGNALS */
495 vcip = cip;
496 osigpipe = (volatile FTPSigProc) signal(SIGPIPE, BrokenData);
497
498 gGotBrokenData = 0;
499 gCanBrokenDataJmp = 0;
500
501#ifdef HAVE_SIGSETJMP
502 sj = sigsetjmp(gBrokenDataJmp, 1);
503#else
504 sj = setjmp(gBrokenDataJmp);
505#endif /* HAVE_SIGSETJMP */
506
507 if (sj != 0) {
508 (void) signal(SIGPIPE, (FTPSigProc) osigpipe);
509 FTPShutdownHost(vcip);
511 return(vcip->errNo);
512 }
513 gCanBrokenDataJmp = 1;
514
515 if (result == 0) {
516 /* This line sets the buffer pointer so that the first thing
517 * BufferGets will do is reset and fill the buffer using
518 * real I/O.
519 */
520 secBufPtr = secondaryBuf + sizeof(secondaryBuf);
521 secBufLimit = (char *) 0;
522 memset(secondaryBuf, 0, sizeof(secondaryBuf));
523
524 for (;;) {
525 memset(line, 0, sizeof(line));
526 if (cip->xferTimeout > 0)
527 (void) alarm(cip->xferTimeout);
528 nread = BufferGets(line, sizeof(line), cip->dataSocket, secondaryBuf, &secBufPtr, &secBufLimit, sizeof(secondaryBuf));
529 if (nread <= 0) {
530 if (nread < 0)
531 break;
532 if (blankLines != 0)
533 (void) AddLine(llines, line);
534 } else {
535 cip->bytesTransferred += (longest_int) nread;
536
537 if ((line[0] == '.') && ((line[1] == '\0') || ((line[1] == '.') && ((line[2] == '\0') || (iscntrl(line[2]))))))
538 continue; /* Skip . and .. */
539
540 (void) AddLine(llines, line);
541 }
542 }
543 if (cip->xferTimeout > 0)
544 (void) alarm(0);
545 result = FTPEndDataCmd(cip, 1);
546 if (result < 0) {
548 cip->errNo = kErrLISTFailed;
549 }
550 result = kNoErr;
551 cip->numListings++;
552 } else if (result == kErrGeneric) {
554 cip->errNo = kErrLISTFailed;
555 }
556 (void) signal(SIGPIPE, (FTPSigProc) osigpipe);
557#endif /* NO_SIGNALS */
558 return (result);
559} /* FTPListToMemory2 */
560
561
562
563
564static void
565AutomaticallyUseASCIIModeDependingOnExtension(const FTPCIPtr cip, const char *const pathName, int *const xtype)
566{
567 if ((*xtype == kTypeBinary) && (cip->asciiFilenameExtensions != NULL)) {
569 /* Matched -- send this file in ASCII mode
570 * instead of binary since it's extension
571 * appears to be that of a text file.
572 */
573 *xtype = kTypeAscii;
574 }
575 }
576} /* AutomaticallyUseASCIIModeDependingOnExtension */
577
578
579
580
581/* The purpose of this is to provide updates for the progress meters
582 * during lags. Return zero if the operation timed-out.
583 */
584static int
586{
587 fd_set ss, ss2;
588 struct timeval tv;
589 int result;
590 int fd;
591 int wsecs;
592 int xferTimeout;
593 int ocancelXfer;
594
595 xferTimeout = cip->xferTimeout;
596 if (xferTimeout < 1)
597 return (1);
598
599 fd = cip->dataSocket;
600 if (fd < 0)
601 return (1);
602
603 ocancelXfer = cip->cancelXfer;
604 wsecs = 0;
605 cip->stalled = 0;
606
607 while ((xferTimeout <= 0) || (wsecs < xferTimeout)) {
608 if ((cip->cancelXfer != 0) && (ocancelXfer == 0)) {
609 /* leave cip->stalled -- could have been stalled and then canceled. */
610 return (1);
611 }
612 FD_ZERO(&ss);
613 FD_SET(fd, &ss);
614 ss2 = ss;
615 tv.tv_sec = 1;
616 tv.tv_usec = 0;
618 if (result == 1) {
619 /* ready */
620 cip->stalled = 0;
621 return (1);
622 } else if (result < 0) {
623 if (errno != EINTR) {
624 perror("select");
625 cip->stalled = 0;
626 return (1);
627 }
628 } else {
629 wsecs++;
630 cip->stalled = wsecs;
631 }
632 FTPUpdateIOTimer(cip);
633 }
634
635#if !defined(NO_SIGNALS)
636 /* Shouldn't get here -- alarm() should have
637 * went off by now.
638 */
639 (void) kill(getpid(), SIGALRM);
640#endif /* NO_SIGNALS */
641
642 cip->dataTimedOut = 1;
643 return (0); /* timed-out */
644} /* WaitForRemoteOutput */
645
646
647
648
649static int
651 const FTPCIPtr cip,
652 const char *const file,
653 const char *volatile dstfile,
654 int xtype,
655 const int fdtouse,
656 const int appendflag,
657 const char *volatile tmppfx,
658 const char *volatile tmpsfx,
659 const int resumeflag,
660 const int deleteflag,
661 const ConfirmResumeUploadProc resumeProc)
662{
663 char *buf, *cp;
664 const char *cmd;
665 const char *odstfile;
666 size_t bufSize;
667 size_t l;
668 int tmpResult, result;
669 int nread, nwrote;
670 volatile int fd;
671 char dstfile2[512];
672#if ASCII_TRANSLATION
673 char *src, *srclim, *dst;
674 int ntowrite;
675 char inbuf[256];
676#endif
677 int fstatrc, statrc;
678 longest_int startPoint = 0;
679 struct Stat st;
680 time_t mdtm;
681#if !defined(NO_SIGNALS)
682 int sj;
683 volatile FTPSigProc osigpipe;
684 volatile FTPCIPtr vcip;
685 volatile int vfd, vfdtouse;
686#endif /* NO_SIGNALS */
687 volatile int vzaction;
689
690 if (cip->buf == NULL) {
691 Error(cip, kDoPerror, "Transfer buffer not allocated.\n");
692 cip->errNo = kErrNoBuf;
693 return (cip->errNo);
694 }
695
696 cip->usingTAR = 0;
697 if (fdtouse < 0) {
699 if (fd < 0) {
700 Error(cip, kDoPerror, "Cannot open local file %s for reading.\n", file);
701 cip->errNo = kErrOpenFailed;
702 return (cip->errNo);
703 }
704 } else {
705 fd = fdtouse;
706 }
707
708 fstatrc = Fstat(fd, &st);
709 if ((fstatrc == 0) && (S_ISDIR(st.st_mode))) {
710 if (fdtouse < 0) {
711 (void) close(fd);
712 }
713 Error(cip, kDontPerror, "%s is a directory.\n", (file != NULL) ? file : "that");
714 cip->errNo = kErrOpenFailed;
715 return (cip->errNo);
716 }
717
718 /* For Put, we can't recover very well if it turns out restart
719 * didn't work, so check beforehand.
720 */
723 if (SetStartOffset(cip, (longest_int) 1) == kNoErr) {
724 /* Now revert -- we still may not end up
725 * doing it.
726 */
727 SetStartOffset(cip, (longest_int) -1);
728 }
729 }
730
731 if (fdtouse < 0) {
733 (void) FTPFileSizeAndModificationTime(cip, dstfile, &startPoint, xtype, &mdtm);
734
735 if (appendflag == kAppendYes) {
737 } else if (
738 (cip->hasREST == kCommandNotAvailable) ||
739 (xtype != kTypeBinary) ||
740 (fstatrc < 0)
741 ) {
743 } else if (resumeflag == kResumeYes) {
745 } else {
747 }
748
749 statrc = -1;
750 if ((mdtm != kModTimeUnknown) || (startPoint != kSizeUnknown)) {
751 /* Then we know the file exists. We will
752 * ask the user what to do, if possible, below.
753 */
754 statrc = 0;
755 } else if ((resumeProc != NoConfirmResumeUploadProc) && (cip->hasMDTM != kCommandAvailable) && (cip->hasSIZE != kCommandAvailable)) {
756 /* We already checked if the file had a filesize
757 * or timestamp above, but if the server indicated
758 * it did not support querying those directly,
759 * we now need to try to determine if the file
760 * exists in a few other ways.
761 */
762 statrc = FTPFileExists2(cip, dstfile, 0, 0, 0, 1, 1);
763 }
764
765 if (
766 (resumeProc != NoConfirmResumeUploadProc) &&
767 (statrc == 0)
768 ) {
769 zaction = (*resumeProc)(file, (longest_int) st.st_size, st.st_mtime, &dstfile, startPoint, mdtm, &startPoint);
770 }
771
772 if (zaction == kConfirmResumeProcSaidCancel) {
773 /* User wants to cancel this file and any
774 * remaining in batch.
775 */
776 cip->errNo = kErrUserCanceled;
777 return (cip->errNo);
778 }
779
780 if (zaction == kConfirmResumeProcSaidBestGuess) {
781 if ((mdtm != kModTimeUnknown) && (st.st_mtime > (mdtm + 1))) {
782 /* Local file is newer than remote,
783 * overwrite the remote file instead
784 * of trying to resume it.
785 *
786 * Note: Add one second fudge factor
787 * for Windows' file timestamps being
788 * imprecise to one second.
789 */
791 } else if ((longest_int) st.st_size == startPoint) {
792 /* Already sent file, done. */
794 } else if ((startPoint != kSizeUnknown) && ((longest_int) st.st_size > startPoint)) {
796 } else {
798 }
799 }
800
801 if (zaction == kConfirmResumeProcSaidSkip) {
802 /* Nothing done, but not an error. */
803 if (fdtouse < 0) {
804 (void) close(fd);
805 }
806 if (deleteflag == kDeleteYes) {
807 if (unlink(file) < 0) {
809 return (cip->errNo);
810 }
811 }
812 return (kNoErr);
813 } else if (zaction == kConfirmResumeProcSaidResume) {
814 /* Resume; proc set the startPoint. */
815 if ((longest_int) st.st_size == startPoint) {
816 /* Already sent file, done. */
817 if (fdtouse < 0) {
818 (void) close(fd);
819 }
820
821 if (deleteflag == kDeleteYes) {
822 if (unlink(file) < 0) {
824 return (cip->errNo);
825 }
826 }
827 return (kNoErr);
828 } else if (Lseek(fd, (off_t) startPoint, SEEK_SET) != (off_t) -1) {
829 cip->startPoint = startPoint;
830 }
831 } else if (zaction == kConfirmResumeProcSaidAppend) {
832 /* append: leave startPoint at zero, we will append everything. */
833 cip->startPoint = startPoint = 0;
834 } else /* if (zaction == kConfirmResumeProcSaidOverwrite) */ {
835 /* overwrite: leave startPoint at zero */
836 cip->startPoint = startPoint = 0;
837 }
838 }
839
840 if ((cip->numUploads == 0) && (cip->dataSocketSBufSize > 0)) {
841 /* If dataSocketSBufSize is non-zero, it means you
842 * want to explicitly try to set the size of the
843 * socket's I/O buffer.
844 *
845 * If it is zero, it means you want to just use the
846 * TCP stack's default value, which is typically
847 * between 8 and 64 kB.
848 *
849 * If you try to set the buffer larger than 64 kB,
850 * the TCP stack should try to use RFC 1323 to
851 * negotiate "TCP Large Windows" which may yield
852 * significant performance gains.
853 */
855 (void) FTPCmd(cip, "SITE STORBUFSIZE %lu", (unsigned long) cip->dataSocketSBufSize);
856 else if (cip->hasSBUFSIZ == kCommandAvailable)
857 (void) FTPCmd(cip, "SITE SBUFSIZ %lu", (unsigned long) cip->dataSocketSBufSize);
858 else if (cip->hasSBUFSZ == kCommandAvailable)
859 (void) FTPCmd(cip, "SITE SBUFSZ %lu", (unsigned long) cip->dataSocketSBufSize);
860 /* At least one server implemenation has RBUFSZ but not
861 * SBUFSZ and instead uses RBUFSZ for both.
862 */
863 else if ((cip->hasSBUFSZ != kCommandAvailable) && (cip->hasRBUFSZ == kCommandAvailable))
864 (void) FTPCmd(cip, "SITE RBUFSZ %lu", (unsigned long) cip->dataSocketSBufSize);
865 else if (cip->hasBUFSIZE == kCommandAvailable)
866 (void) FTPCmd(cip, "SITE BUFSIZE %lu", (unsigned long) cip->dataSocketSBufSize);
867 }
868
869#ifdef NO_SIGNALS
870 vzaction = zaction;
871#else /* NO_SIGNALS */
872 vcip = cip;
873 vfdtouse = fdtouse;
874 vfd = fd;
875 vzaction = zaction;
876 osigpipe = (volatile FTPSigProc) signal(SIGPIPE, BrokenData);
877
878 gGotBrokenData = 0;
879 gCanBrokenDataJmp = 0;
880
881#ifdef HAVE_SIGSETJMP
882 sj = sigsetjmp(gBrokenDataJmp, 1);
883#else
884 sj = setjmp(gBrokenDataJmp);
885#endif /* HAVE_SIGSETJMP */
886
887 if (sj != 0) {
888 (void) signal(SIGPIPE, (FTPSigProc) osigpipe);
889 if (vfdtouse < 0) {
890 (void) close(vfd);
891 }
892 FTPShutdownHost(vcip);
894 return(vcip->errNo);
895 }
896 gCanBrokenDataJmp = 1;
897#endif /* NO_SIGNALS */
898
899 if (vzaction == kConfirmResumeProcSaidAppend) {
900 cmd = "APPE";
901 tmppfx = ""; /* Can't use that here. */
902 tmpsfx = "";
903 } else {
904 cmd = "STOR";
905 if (tmppfx == NULL)
906 tmppfx = "";
907 if (tmpsfx == NULL)
908 tmpsfx = "";
909 }
910
911 odstfile = dstfile;
912 if ((tmppfx[0] != '\0') || (tmpsfx[0] != '\0')) {
913 cp = strrchr(dstfile, '/');
914 if (cp == NULL)
915 cp = strrchr(dstfile, '\\');
916 if (cp == NULL) {
917 (void) STRNCPY(dstfile2, tmppfx);
918 (void) STRNCAT(dstfile2, dstfile);
919 (void) STRNCAT(dstfile2, tmpsfx);
920 } else {
921 cp++;
922 l = (size_t) (cp - dstfile);
923 (void) STRNCPY(dstfile2, dstfile);
924 dstfile2[l] = '\0'; /* Nuke stuff after / */
925 (void) STRNCAT(dstfile2, tmppfx);
926 (void) STRNCAT(dstfile2, cp);
927 (void) STRNCAT(dstfile2, tmpsfx);
928 }
929 dstfile = dstfile2;
930 }
931
932 tmpResult = FTPStartDataCmd(
933 cip,
935 xtype,
936 startPoint,
937 "%s %s",
938 cmd,
939 dstfile
940 );
941
942 if (tmpResult < 0) {
943 cip->errNo = tmpResult;
944 if (fdtouse < 0) {
945 (void) close(fd);
946 }
947#if !defined(NO_SIGNALS)
948 (void) signal(SIGPIPE, (FTPSigProc) osigpipe);
949#endif /* NO_SIGNALS */
950 return (cip->errNo);
951 }
952
953 if ((startPoint != 0) && (cip->startPoint == 0)) {
954 /* Remote could not or would not set the start offset
955 * to what we wanted.
956 *
957 * So now we have to undo our seek.
958 */
959 if (Lseek(fd, (off_t) 0, SEEK_SET) != (off_t) 0) {
960 cip->errNo = kErrLseekFailed;
961 if (fdtouse < 0) {
962 (void) close(fd);
963 }
964#if !defined(NO_SIGNALS)
965 (void) signal(SIGPIPE, (FTPSigProc) osigpipe);
966#endif /* NO_SIGNALS */
967 return (cip->errNo);
968 }
969 startPoint = 0;
970 }
971
972 result = kNoErr;
973 buf = cip->buf;
974 bufSize = cip->bufSize;
975
976 FTPInitIOTimer(cip);
977 if ((fstatrc == 0) && (S_ISREG(st.st_mode) != 0)) {
978 cip->expectedSize = (longest_int) st.st_size;
979 cip->mdtm = st.st_mtime;
980 }
981 cip->lname = file; /* could be NULL */
982 cip->rname = odstfile;
983 if (fdtouse >= 0)
984 cip->useProgressMeter = 0;
985 FTPStartIOTimer(cip);
986
987 /* Note: On Windows, we don't have to do anything special
988 * for ASCII mode, since Net ASCII's end-of-line sequence
989 * corresponds to the same thing used for DOS/Windows.
990 */
991
992#if ASCII_TRANSLATION
993 if (xtype == kTypeAscii) {
994 /* ascii */
995 for (;;) {
996#if !defined(NO_SIGNALS)
997 gCanBrokenDataJmp = 0;
998#endif /* NO_SIGNALS */
999 nread = read(fd, inbuf, sizeof(inbuf));
1000 if (nread < 0) {
1001 if (errno == EINTR) {
1002 continue;
1003 } else {
1005 cip->errNo = kErrReadFailed;
1006 Error(cip, kDoPerror, "Local read failed.\n");
1007 }
1008 break;
1009 } else if (nread == 0) {
1010 break;
1011 }
1012 cip->bytesTransferred += (longest_int) nread;
1013
1014#if !defined(NO_SIGNALS)
1015 gCanBrokenDataJmp = 1;
1016#endif /* NO_SIGNALS */
1017 src = inbuf;
1018 srclim = src + nread;
1019 dst = cip->buf; /* must be 2x sizeof inbuf or more. */
1020 while (src < srclim) {
1021 if (*src == '\n')
1022 *dst++ = '\r';
1023 *dst++ = *src++;
1024 }
1025 ntowrite = (size_t) (dst - cip->buf);
1026 cp = cip->buf;
1027
1028#if !defined(NO_SIGNALS)
1029 if (cip->xferTimeout > 0)
1030 (void) alarm(cip->xferTimeout);
1031#endif /* NO_SIGNALS */
1032 do {
1033 if (! WaitForRemoteOutput(cip)) { /* could set cancelXfer */
1034 cip->errNo = result = kErrDataTimedOut;
1035 Error(cip, kDontPerror, "Remote write timed out.\n");
1036 goto brk;
1037 }
1038 if (cip->cancelXfer > 0) {
1041 goto brk;
1042 }
1043
1044#ifdef NO_SIGNALS
1045 nwrote = SWrite(cip->dataSocket, cp, (size_t) ntowrite, (int) cip->xferTimeout, kNoFirstSelect);
1046 if (nwrote < 0) {
1047 if (nwrote == kTimeoutErr) {
1048 cip->errNo = result = kErrDataTimedOut;
1049 Error(cip, kDontPerror, "Remote write timed out.\n");
1050 } else if ((gGotBrokenData != 0) || (errno == EPIPE)) {
1052 errno = EPIPE;
1053 Error(cip, kDoPerror, "Lost data connection to remote host.\n");
1054 } else if (errno == EINTR) {
1055 continue;
1056 } else {
1058 Error(cip, kDoPerror, "Remote write failed.\n");
1059 }
1060 (void) shutdown(cip->dataSocket, 2);
1061 goto brk;
1062 }
1063#else /* NO_SIGNALS */
1064 nwrote = write(cip->dataSocket, cp, ntowrite);
1065 if (nwrote < 0) {
1066 if ((gGotBrokenData != 0) || (errno == EPIPE)) {
1068 errno = EPIPE;
1069 Error(cip, kDoPerror, "Lost data connection to remote host.\n");
1070 } else if (errno == EINTR) {
1071 continue;
1072 } else {
1074 Error(cip, kDoPerror, "Remote write failed.\n");
1075 }
1076 (void) shutdown(cip->dataSocket, 2);
1077 goto brk;
1078 }
1079#endif /* NO_SIGNALS */
1080 cp += nwrote;
1081 ntowrite -= nwrote;
1082 } while (ntowrite > 0);
1083 FTPUpdateIOTimer(cip);
1084 }
1085 } else
1086#endif /* ASCII_TRANSLATION */
1087 {
1088 /* binary */
1089 for (;;) {
1090#if !defined(NO_SIGNALS)
1091 gCanBrokenDataJmp = 0;
1092#endif /* NO_SIGNALS */
1093 cp = buf;
1094 nread = read(fd, cp, bufSize);
1095 if (nread < 0) {
1096 if (errno == EINTR) {
1097 continue;
1098 } else {
1100 cip->errNo = kErrReadFailed;
1101 Error(cip, kDoPerror, "Local read failed.\n");
1102 }
1103 break;
1104 } else if (nread == 0) {
1105 break;
1106 }
1107 cip->bytesTransferred += (longest_int) nread;
1108
1109#if !defined(NO_SIGNALS)
1110 gCanBrokenDataJmp = 1;
1111 if (cip->xferTimeout > 0)
1112 (void) alarm(cip->xferTimeout);
1113#endif /* NO_SIGNALS */
1114 do {
1115 if (! WaitForRemoteOutput(cip)) { /* could set cancelXfer */
1116 cip->errNo = result = kErrDataTimedOut;
1117 Error(cip, kDontPerror, "Remote write timed out.\n");
1118 goto brk;
1119 }
1120 if (cip->cancelXfer > 0) {
1123 goto brk;
1124 }
1125
1126#ifdef NO_SIGNALS
1127 nwrote = SWrite(cip->dataSocket, cp, (size_t) nread, (int) cip->xferTimeout, kNoFirstSelect);
1128 if (nwrote < 0) {
1129 if (nwrote == kTimeoutErr) {
1130 cip->errNo = result = kErrDataTimedOut;
1131 Error(cip, kDontPerror, "Remote write timed out.\n");
1132 } else if ((gGotBrokenData != 0) || (errno == EPIPE)) {
1134 errno = EPIPE;
1135 Error(cip, kDoPerror, "Lost data connection to remote host.\n");
1136 } else if (errno == EINTR) {
1137 continue;
1138 } else {
1140 Error(cip, kDoPerror, "Remote write failed.\n");
1141 }
1142 (void) shutdown(cip->dataSocket, 2);
1143 cip->dataSocket = -1;
1144 goto brk;
1145 }
1146#else /* NO_SIGNALS */
1147 nwrote = write(cip->dataSocket, cp, nread);
1148 if (nwrote < 0) {
1149 if ((gGotBrokenData != 0) || (errno == EPIPE)) {
1151 errno = EPIPE;
1152 Error(cip, kDoPerror, "Lost data connection to remote host.\n");
1153 } else if (errno == EINTR) {
1154 continue;
1155 } else {
1157 Error(cip, kDoPerror, "Remote write failed.\n");
1158 }
1159 (void) shutdown(cip->dataSocket, 2);
1160 cip->dataSocket = -1;
1161 goto brk;
1162 }
1163#endif /* NO_SIGNALS */
1164 cp += nwrote;
1165 nread -= nwrote;
1166 } while (nread > 0);
1167 FTPUpdateIOTimer(cip);
1168 }
1169 }
1170brk:
1171
1172 if (fdtouse < 0) {
1173 (void) Fstat(fd, &st);
1174 }
1175
1176 if (fdtouse < 0) {
1177 if (shutdown(fd, 1) == 0) {
1178 /* This looks very bizarre, since
1179 * we will be checking the socket
1180 * for readability here!
1181 *
1182 * The reason for this is that we
1183 * want to be able to timeout a
1184 * small put. So, we close the
1185 * write end of the socket first,
1186 * which tells the server we're
1187 * done writing. We then wait
1188 * for the server to close down
1189 * the whole socket, which tells
1190 * us that the file was completed.
1191 */
1192 (void) WaitForRemoteInput(cip); /* Close could block. */
1193 }
1194 }
1195
1196#if !defined(NO_SIGNALS)
1197 gCanBrokenDataJmp = 0;
1198 if (cip->xferTimeout > 0)
1199 (void) alarm(0);
1200#endif /* NO_SIGNALS */
1201 tmpResult = FTPEndDataCmd(cip, 1);
1202 if ((tmpResult < 0) && (result == kNoErr)) {
1203 cip->errNo = result = kErrSTORFailed;
1204 }
1205 FTPStopIOTimer(cip);
1206
1207 if (fdtouse < 0) {
1208 /* If they gave us a descriptor (fdtouse >= 0),
1209 * leave it open, otherwise we opened it, so
1210 * we need to dispose of it.
1211 */
1212 (void) close(fd);
1213 fd = -1;
1214 }
1215
1216 if (result == kNoErr) {
1217 /* The store succeeded; If we were
1218 * uploading to a temporary file,
1219 * move the new file to the new name.
1220 */
1221 cip->numUploads++;
1222
1223 if ((tmppfx[0] != '\0') || (tmpsfx[0] != '\0')) {
1224 if ((result = FTPRename(cip, dstfile, odstfile)) < 0) {
1225 /* May fail if file was already there,
1226 * so delete the old one so we can move
1227 * over it.
1228 */
1229 if (FTPDelete(cip, odstfile, kRecursiveNo, kGlobNo) == kNoErr) {
1230 result = FTPRename(cip, dstfile, odstfile);
1231 if (result < 0) {
1232 Error(cip, kDontPerror, "Could not rename %s to %s: %s.\n", dstfile, odstfile, FTPStrError(cip->errNo));
1233 }
1234 } else {
1235 Error(cip, kDontPerror, "Could not delete old %s, so could not rename %s to that: %s\n", odstfile, dstfile, FTPStrError(cip->errNo));
1236 }
1237 }
1238 }
1239
1240 if (FTPUtime(cip, odstfile, st.st_atime, st.st_mtime, st.st_ctime) != kNoErr) {
1241 if (cip->errNo != kErrUTIMENotAvailable)
1242 Error(cip, kDontPerror, "Could not preserve times for %s: %s.\n", odstfile, FTPStrError(cip->errNo));
1243 }
1244
1245 if (deleteflag == kDeleteYes) {
1246 if (unlink(file) < 0) {
1248 }
1249 }
1250 }
1251
1252#if !defined(NO_SIGNALS)
1253 (void) signal(SIGPIPE, (FTPSigProc) osigpipe);
1254#endif /* NO_SIGNALS */
1255 return (result);
1256} /* FTPPutOneF */
1257
1258
1259
1260
1261int
1263 const FTPCIPtr cip,
1264 const char *const file,
1265 const char *const dstfile,
1266 const int xtype,
1267 const int fdtouse,
1268 const int appendflag,
1269 const char *const tmppfx,
1270 const char *const tmpsfx,
1271 const int resumeflag,
1272 const int deleteflag,
1273 const ConfirmResumeUploadProc resumeProc,
1274 int UNUSED(reserved))
1275{
1276 int result;
1277
1279 if (cip == NULL)
1280 return (kErrBadParameter);
1281 if (strcmp(cip->magic, kLibraryMagic))
1282 return (kErrBadMagic);
1283
1284 if ((dstfile == NULL) || (dstfile[0] == '\0'))
1285 return (kErrBadParameter);
1286 if (fdtouse < 0) {
1287 if ((file == NULL) || (file[0] == '\0'))
1288 return (kErrBadParameter);
1289 }
1290 result = FTPPutOneF(cip, file, dstfile, xtype, fdtouse, appendflag, tmppfx, tmpsfx, resumeflag, deleteflag, resumeProc);
1291 return (result);
1292} /* FTPPutOneFile3 */
1293
1294
1295
1296
1297int
1299 const FTPCIPtr cip,
1300 const char *const pattern,
1301 const char *const dstdir1,
1302 const int recurse,
1303 const int doGlob,
1304 const int xtype,
1305 int appendflag,
1306 const char *const tmppfx,
1307 const char *const tmpsfx,
1308 const int resumeflag,
1309 const int deleteflag,
1310 const ConfirmResumeUploadProc resumeProc,
1311 int UNUSED(reserved))
1312{
1313 LineList globList;
1314 FileInfoList files;
1315 FileInfoPtr filePtr;
1316 int batchResult;
1317 int result;
1318 const char *dstdir;
1319 char dstdir2[512];
1320
1322 if (cip == NULL)
1323 return (kErrBadParameter);
1324 if (strcmp(cip->magic, kLibraryMagic))
1325 return (kErrBadMagic);
1326
1327 if (dstdir1 == NULL) {
1328 dstdir = NULL;
1329 } else {
1330 dstdir = STRNCPY(dstdir2, dstdir1);
1332 }
1333
1334 (void) FTPLocalGlob(cip, &globList, pattern, doGlob);
1335 if (recurse == kRecursiveYes) {
1336 appendflag = kAppendNo;
1337 (void) FTPLocalRecursiveFileList(cip, &globList, &files);
1338 if (files.first == NULL) {
1341 }
1342 (void) ComputeRNames(&files, dstdir, 0, 1);
1343 } else {
1344 (void) LineListToFileInfoList(&globList, &files);
1345 (void) ComputeLNames(&files, NULL, NULL, 1);
1346 (void) ComputeRNames(&files, dstdir, 0, 0);
1347 }
1348 DisposeLineListContents(&globList);
1349
1350#if 0
1351 for (filePtr = files.first; filePtr != NULL; filePtr = filePtr->next) {
1352 PrintF(cip, " R=%s, L=%s, 2=%s, size=%d, mdtm=%u, type=%c\n",
1353 filePtr->rname,
1354 filePtr->lname,
1355 filePtr->rlinkto ? filePtr->rlinkto : "",
1356 filePtr->size,
1357 (unsigned int) filePtr->mdtm,
1358 filePtr->type
1359 );
1360 }
1361#endif
1362
1363 batchResult = kNoErr;
1364 for (filePtr = files.first; filePtr != NULL; filePtr = filePtr->next) {
1365 if (cip->connected == 0) {
1366 if (batchResult == kNoErr)
1367 batchResult = kErrRemoteHostClosedConnection;
1368 break;
1369 }
1370 if (filePtr->type == 'd') {
1371 /* mkdir */
1373 result = FTPMkdir(cip, filePtr->rname, kRecursiveNo);
1374 if (result != kNoErr)
1375 batchResult = result;
1376#ifdef HAVE_SYMLINK
1377 } else if (filePtr->type == 'l') {
1378 /* symlink */
1379 /* no RFC way to create the link, though. */
1380 if ((filePtr->rlinkto != NULL) && (filePtr->rlinkto[0] != '\0'))
1381 (void) FTPSymlink(cip, filePtr->rname, filePtr->rlinkto);
1382#endif
1383 } else if (recurse != kRecursiveYes) {
1384 result = FTPPutOneF(cip, filePtr->lname, filePtr->rname, xtype, -1, appendflag, tmppfx, tmpsfx, resumeflag, deleteflag, resumeProc);
1385 if (files.nFileInfos == 1) {
1386 if (result != kNoErr)
1387 batchResult = result;
1388 } else {
1390 batchResult = result;
1391 }
1392 if (result == kErrUserCanceled)
1393 cip->cancelXfer = 1;
1394 if (cip->cancelXfer > 0)
1395 break;
1396 } else {
1397 result = FTPPutOneF(cip, filePtr->lname, filePtr->rname, xtype, -1, appendflag, tmppfx, tmpsfx, resumeflag, deleteflag, resumeProc);
1398 if (files.nFileInfos == 1) {
1399 if (result != kNoErr)
1400 batchResult = result;
1401 } else {
1403 batchResult = result;
1404 }
1405 if (result == kErrUserCanceled)
1406 cip->cancelXfer = 1;
1407 if (cip->cancelXfer > 0)
1408 break;
1409 }
1410 }
1412 if (batchResult < 0)
1413 cip->errNo = batchResult;
1414 return (batchResult);
1415} /* FTPPutFiles3 */
1416
1417
1418
1419
1420/* The purpose of this is to provide updates for the progress meters
1421 * during lags. Return zero if the operation timed-out.
1422 */
1423static int
1425{
1426 fd_set ss, ss2;
1427 struct timeval tv;
1428 int result;
1429 int fd;
1430 int wsecs;
1431 int xferTimeout;
1432 int ocancelXfer;
1433
1434 xferTimeout = cip->xferTimeout;
1435 if (xferTimeout < 1)
1436 return (1);
1437
1438 fd = cip->dataSocket;
1439 if (fd < 0)
1440 return (1);
1441
1442 ocancelXfer = cip->cancelXfer;
1443 wsecs = 0;
1444 cip->stalled = 0;
1445
1446 while ((xferTimeout <= 0) || (wsecs < xferTimeout)) {
1447 if ((cip->cancelXfer != 0) && (ocancelXfer == 0)) {
1448 /* leave cip->stalled -- could have been stalled and then canceled. */
1449 return (1);
1450 }
1451 FD_ZERO(&ss);
1452 FD_SET(fd, &ss);
1453 ss2 = ss;
1454 tv.tv_sec = 1;
1455 tv.tv_usec = 0;
1457 if (result == 1) {
1458 /* ready */
1459 cip->stalled = 0;
1460 return (1);
1461 } else if (result < 0) {
1462 if (result != EINTR) {
1463 perror("select");
1464 cip->stalled = 0;
1465 return (1);
1466 }
1467 } else {
1468 wsecs++;
1469 cip->stalled = wsecs;
1470 }
1471 FTPUpdateIOTimer(cip);
1472 }
1473
1474#if !defined(NO_SIGNALS)
1475 /* Shouldn't get here -- alarm() should have
1476 * went off by now.
1477 */
1478 (void) kill(getpid(), SIGALRM);
1479#endif /* NO_SIGNALS */
1480
1481 cip->dataTimedOut = 1;
1482 return (0); /* timed-out */
1483} /* WaitForRemoteInput */
1484
1485
1486
1487
1488/* Nice for UNIX, but not necessary otherwise. */
1489#ifdef TAR
1490
1491static int
1492OpenTar(const FTPCIPtr cip, const char *const dstdir, int *const pid)
1493{
1494 int pipe1[2];
1495 int pid1;
1496 int i;
1497 char *argv[8];
1498
1499 *pid = -1;
1500
1501 if (access(TAR, X_OK) < 0) {
1502 /* Path to TAR is invalid. */
1503 return (-1);
1504 }
1505
1506 if (pipe(pipe1) < 0) {
1507 Error(cip, kDoPerror, "pipe to Tar failed");
1508 return (-1);
1509 }
1510
1511 pid1 = (int) fork();
1512 if (pid1 < 0) {
1513 (void) close(pipe1[0]);
1514 (void) close(pipe1[1]);
1515 return (-1);
1516 } else if (pid1 == 0) {
1517 /* Child */
1518 if ((dstdir != NULL) && (dstdir[0] != '\0') && (chdir(dstdir) < 0)) {
1519 Error(cip, kDoPerror, "tar chdir to %s failed", dstdir);
1520 exit(1);
1521 }
1522 (void) close(pipe1[1]); /* close write end */
1523 (void) dup2(pipe1[0], 0); /* use read end on stdin */
1524 (void) close(pipe1[0]);
1525
1526 for (i=3; i<256; i++)
1527 (void) close(i);
1528
1529 argv[0] = (char *) "tar";
1530 argv[1] = (char *) "xpf";
1531 argv[2] = (char *) "-";
1532 argv[3] = NULL;
1533
1534 (void) execv(TAR, argv);
1535 exit(1);
1536 }
1537
1538 /* Parent */
1539 *pid = pid1;
1540
1541 (void) close(pipe1[0]); /* close read end */
1542 return (pipe1[1]); /* use write end */
1543} /* OpenTar */
1544
1545
1546
1547
1548static int
1549FTPGetOneTarF(const FTPCIPtr cip, const char *file, const char *const dstdir)
1550{
1551 char *buf;
1552 size_t bufSize;
1553 int tmpResult;
1554 volatile int result;
1555 int nread, nwrote;
1556 volatile int fd;
1557 volatile int vfd;
1558 const char *volatile vfile;
1559#ifndef NO_SIGNALS
1560 int sj;
1561 volatile FTPSigProc osigpipe;
1562 volatile FTPCIPtr vcip;
1563#endif
1564 int pid, status;
1565 char savedCwd[512];
1566 char *volatile basecp;
1567
1568 result = kNoErr;
1569 cip->usingTAR = 0;
1570
1571 if ((file[0] == '\0') || ((file[0] == '/') && (file[1] == '\0'))) {
1572 /* It was "/"
1573 * We can't do that, because "get /.tar"
1574 * or "get .tar" does not work.
1575 */
1577 cip->errNo = kErrOpenFailed;
1578 return (result);
1579 }
1580
1581 if (FTPCmd(cip, "MDTM %s.tar", file) == 2) {
1582 /* Better not use this method since there is
1583 * no way to tell if the server would use the
1584 * existing .tar or do a new one on the fly.
1585 */
1587 cip->errNo = kErrOpenFailed;
1588 return (result);
1589 }
1590
1591 basecp = strrchr(file, '/');
1592 if (basecp != NULL)
1593 basecp = strrchr(file, '\\');
1594 if (basecp != NULL) {
1595 /* Need to cd to the parent directory and get it
1596 * from there.
1597 */
1598 if (FTPGetCWD(cip, savedCwd, sizeof(savedCwd)) != 0) {
1600 cip->errNo = kErrOpenFailed;
1601 return (result);
1602 }
1603 result = FTPChdir(cip, file);
1604 if (result != kNoErr) {
1605 return (result);
1606 }
1607 result = FTPChdir(cip, "..");
1608 if (result != kNoErr) {
1609 (void) FTPChdir(cip, savedCwd);
1610 return (result);
1611 }
1612 file = basecp + 1;
1613 }
1614
1615 fd = OpenTar(cip, dstdir, &pid);
1616 if (fd < 0) {
1618 cip->errNo = kErrOpenFailed;
1619 if (basecp != NULL)
1620 (void) FTPChdir(cip, savedCwd);
1621 return (result);
1622 }
1623
1624 vfd = fd;
1625 vfile = file;
1626
1627#ifndef NO_SIGNALS
1628 vcip = cip;
1629 osigpipe = (volatile FTPSigProc) signal(SIGPIPE, BrokenData);
1630
1631 gGotBrokenData = 0;
1632 gCanBrokenDataJmp = 0;
1633
1634#ifdef HAVE_SIGSETJMP
1635 sj = sigsetjmp(gBrokenDataJmp, 1);
1636#else
1637 sj = setjmp(gBrokenDataJmp);
1638#endif /* HAVE_SIGSETJMP */
1639
1640 if (sj != 0) {
1641 (void) signal(SIGPIPE, (FTPSigProc) osigpipe);
1642 FTPShutdownHost(vcip);
1643
1645 (void) close(vfd);
1646 for (;;) {
1647#ifdef HAVE_WAITPID
1648 if ((waitpid(pid, &status, 0) < 0) && (errno != EINTR))
1649 break;
1650#else
1651 if ((wait(&status) < 0) && (errno != EINTR))
1652 break;
1653#endif
1654 if (WIFEXITED(status) || WIFSIGNALED(status))
1655 break; /* done */
1656 }
1657 if (basecp != NULL)
1658 (void) FTPChdir(cip, savedCwd);
1660 return(vcip->errNo);
1661 }
1662 gCanBrokenDataJmp = 1;
1663
1664#endif /* NO_SIGNALS */
1665
1666 tmpResult = FTPStartDataCmd(cip, kNetReading, kTypeBinary, (longest_int) 0, "RETR %s.tar", vfile);
1667
1668 if (tmpResult < 0) {
1669 result = tmpResult;
1670 if (result == kErrGeneric)
1672 cip->errNo = result;
1673
1674#ifndef NO_SIGNALS
1676#endif
1677 (void) close(vfd);
1678 for (;;) {
1679#ifdef HAVE_WAITPID
1680 if ((waitpid(pid, &status, 0) < 0) && (errno != EINTR))
1681 break;
1682#else
1683 if ((wait(&status) < 0) && (errno != EINTR))
1684 break;
1685#endif
1686 if (WIFEXITED(status) || WIFSIGNALED(status))
1687 break; /* done */
1688 }
1689
1690#ifndef NO_SIGNALS
1691 (void) signal(SIGPIPE, (FTPSigProc) osigpipe);
1692#endif
1693 if (basecp != NULL)
1694 (void) FTPChdir(cip, savedCwd);
1695 return (result);
1696 }
1697
1698 cip->usingTAR = 1;
1699 buf = cip->buf;
1700 bufSize = cip->bufSize;
1701
1702 FTPInitIOTimer(cip);
1703 cip->lname = vfile; /* could be NULL */
1704 cip->rname = vfile;
1705 FTPStartIOTimer(cip);
1706
1707 /* Binary */
1708 for (;;) {
1709 if (! WaitForRemoteInput(cip)) { /* could set cancelXfer */
1710 cip->errNo = result = kErrDataTimedOut;
1711 Error(cip, kDontPerror, "Remote read timed out.\n");
1712 break;
1713 }
1714 if (cip->cancelXfer > 0) {
1717 break;
1718 }
1719#if !defined(NO_SIGNALS)
1720 gCanBrokenDataJmp = 1;
1721 if (cip->xferTimeout > 0)
1722 (void) alarm(cip->xferTimeout);
1723#endif /* NO_SIGNALS */
1724#ifdef NO_SIGNALS
1726 if (nread == kTimeoutErr) {
1727 cip->errNo = result = kErrDataTimedOut;
1728 Error(cip, kDontPerror, "Remote read timed out.\n");
1729 break;
1730 } else if (nread < 0) {
1731 if (errno == EINTR)
1732 continue;
1733 Error(cip, kDoPerror, "Remote read failed.\n");
1736 break;
1737 } else if (nread == 0) {
1738 break;
1739 }
1740#else
1741 nread = read(cip->dataSocket, buf, bufSize);
1742 if (nread < 0) {
1743 if (errno == EINTR)
1744 continue;
1745 Error(cip, kDoPerror, "Remote read failed.\n");
1748 break;
1749 } else if (nread == 0) {
1750 break;
1751 }
1752 gCanBrokenDataJmp = 0;
1753#endif
1754
1755 nwrote = write(fd, buf, nread);
1756 if (nwrote != nread) {
1757 if ((gGotBrokenData != 0) || (errno == EPIPE)) {
1759 cip->errNo = kErrWriteFailed;
1760 errno = EPIPE;
1761 } else {
1762 Error(cip, kDoPerror, "Local write failed.\n");
1764 cip->errNo = kErrWriteFailed;
1765 }
1766 break;
1767 }
1768 cip->bytesTransferred += (longest_int) nread;
1769 FTPUpdateIOTimer(cip);
1770 }
1771
1772#if !defined(NO_SIGNALS)
1773 if (cip->xferTimeout > 0)
1774 (void) alarm(0);
1775 gCanBrokenDataJmp = 0;
1776#endif /* NO_SIGNALS */
1777
1778 (void) close(fd);
1779 for (;;) {
1780#ifdef HAVE_WAITPID
1781 if ((waitpid(pid, &status, 0) < 0) && (errno != EINTR))
1782 break;
1783#else
1784 if ((wait(&status) < 0) && (errno != EINTR))
1785 break;
1786#endif
1787 if (WIFEXITED(status) || WIFSIGNALED(status))
1788 break; /* done */
1789 }
1790
1791 tmpResult = FTPEndDataCmd(cip, 1);
1792 if ((tmpResult < 0) && (result == 0)) {
1794 cip->errNo = kErrRETRFailed;
1795 }
1796 FTPStopIOTimer(cip);
1797#if !defined(NO_SIGNALS)
1798 (void) signal(SIGPIPE, (FTPSigProc) osigpipe);
1799#endif
1800
1801 if ((result == 0) && (cip->bytesTransferred == 0)) {
1803 cip->errNo = kErrOpenFailed;
1804 }
1805 if (basecp != NULL)
1806 (void) FTPChdir(cip, savedCwd);
1807 return (result);
1808} /* FTPGetOneTarF */
1809
1810#endif /* TAR */
1811
1812
1813
1814
1815
1816static int
1818 const FTPCIPtr cip,
1819 const char *const file,
1820 const char *dstfile,
1821 int xtype,
1822 const int fdtouse,
1823 longest_int expectedSize,
1824 time_t mdtm,
1825 const int resumeflag,
1826 const int appendflag,
1827 const int deleteflag,
1828 const ConfirmResumeDownloadProc resumeProc)
1829{
1830 char *buf;
1831 size_t bufSize;
1832 int tmpResult;
1833 volatile int result;
1834 int nread, nwrote;
1835 volatile int fd;
1836#if ASCII_TRANSLATION
1837 char *src, *srclim;
1838 char *dst, *dstlim;
1839 char outbuf[512];
1840#endif
1841 volatile longest_int startPoint = 0;
1842 struct utimbuf ut;
1843 struct Stat st;
1844#if !defined(NO_SIGNALS)
1845 volatile FTPSigProc osigpipe;
1846 volatile FTPCIPtr vcip;
1847 volatile int vfd, vfdtouse;
1848 int sj;
1849#endif /* NO_SIGNALS */
1850 volatile int created = 0;
1851 int zaction = kConfirmResumeProcSaidBestGuess;
1852 int statrc;
1853 int noMdtmCheck;
1854 time_t now;
1855
1856 if (cip->buf == NULL) {
1857 Error(cip, kDoPerror, "Transfer buffer not allocated.\n");
1858 cip->errNo = kErrNoBuf;
1859 return (cip->errNo);
1860 }
1861
1862 result = kNoErr;
1863 cip->usingTAR = 0;
1864
1865 if (fdtouse < 0) {
1866 /* Only ask for extended information
1867 * if we have the name of the file
1868 * and we didn't already have the
1869 * info.
1870 *
1871 * Always ask for the modification time,
1872 * because even if it was passed in it
1873 * may not be accurate. This is often
1874 * the case when it came from an ls
1875 * listing, in which the local time
1876 * zone could be a factor.
1877 *
1878 */
1879
1881 if (expectedSize == kSizeUnknown) {
1882 (void) FTPFileSizeAndModificationTime(cip, file, &expectedSize, xtype, &mdtm);
1883 } else {
1884 (void) FTPFileModificationTime(cip, file, &mdtm);
1885 }
1886
1887 /* For Get, we can't recover very well if it turns out restart
1888 * didn't work, so check beforehand.
1889 */
1890 if ((resumeflag == kResumeYes) || (resumeProc != NoConfirmResumeDownloadProc)) {
1893 if (SetStartOffset(cip, (longest_int) 1) == kNoErr) {
1894 /* Now revert -- we still may not end up
1895 * doing it.
1896 */
1897 SetStartOffset(cip, (longest_int) -1);
1898 }
1899 }
1900 }
1901
1902 if (appendflag == kAppendYes) {
1904 } else if (cip->hasREST == kCommandNotAvailable) {
1906 } else if (resumeflag == kResumeYes) {
1908 } else {
1910 }
1911
1912 statrc = Stat(dstfile, &st);
1913 if (statrc == 0) {
1914 if (resumeProc != NULL) {
1915 zaction = (*resumeProc)(
1916 &dstfile,
1917 (longest_int) st.st_size,
1918 st.st_mtime,
1919 file,
1920 expectedSize,
1921 mdtm,
1922 &startPoint
1923 );
1924 }
1925
1926 if (zaction == kConfirmResumeProcSaidBestGuess) {
1927 if (expectedSize != kSizeUnknown) {
1928 /* We know the size of the remote file,
1929 * and we have a local file too.
1930 *
1931 * Try and decide if we need to get
1932 * the entire file, or just part of it.
1933 */
1934
1935 startPoint = (longest_int) st.st_size;
1937
1938 /* If the local file exists and has a recent
1939 * modification time (< 12 hours) and
1940 * the remote file's modtime is not recent,
1941 * then heuristically conclude that the
1942 * local modtime should not be trusted
1943 * (i.e. user killed the process before
1944 * the local modtime could be preserved).
1945 */
1946 noMdtmCheck = 0;
1947 if (mdtm != kModTimeUnknown) {
1948 time(&now);
1949 if ((st.st_mtime > now) || (((now - st.st_mtime) < 46200) && ((now - mdtm) >= 46200)))
1950 noMdtmCheck = 1;
1951 }
1952
1953 if ((mdtm == kModTimeUnknown) || (noMdtmCheck != 0)) {
1954 /* Can't use the timestamps as an aid. */
1955 if (startPoint == expectedSize) {
1956 /* Don't go to all the trouble of downloading nothing. */
1958 if (deleteflag == kDeleteYes)
1960 return (cip->errNo);
1961 } else if (startPoint > expectedSize) {
1962 /* Panic; odds are the file we have
1963 * was a different file altogether,
1964 * since it is larger than the
1965 * remote copy. Re-do it all.
1966 */
1968 } /* else resume at startPoint */
1969 } else if ((mdtm == st.st_mtime) || (mdtm == (st.st_mtime - 1)) || (mdtm == (st.st_mtime + 1))) {
1970 /* File has the same time.
1971 * Note: Windows' file timestamps can be off by one second!
1972 */
1973 if (startPoint == expectedSize) {
1974 /* Don't go to all the trouble of downloading nothing. */
1976 if (deleteflag == kDeleteYes)
1978 return (cip->errNo);
1979 } else if (startPoint > expectedSize) {
1980 /* Panic; odds are the file we have
1981 * was a different file altogether,
1982 * since it is larger than the
1983 * remote copy. Re-do it all.
1984 */
1986 } else {
1987 /* We have a file by the same time,
1988 * but smaller start point. Leave
1989 * the startpoint as is since it
1990 * is most likely valid.
1991 */
1992 }
1993 } else if (mdtm < st.st_mtime) {
1994 /* Remote file is older than
1995 * local file. Don't overwrite
1996 * our file.
1997 */
1999 return (cip->errNo);
2000 } else /* if (mdtm > st.st_mtime) */ {
2001 /* File has a newer timestamp
2002 * altogether, assume the remote
2003 * file is an entirely new file
2004 * and replace ours with it.
2005 */
2007 }
2008 } else {
2010 }
2011 }
2012 } else {
2014 }
2015
2016 if (zaction == kConfirmResumeProcSaidCancel) {
2017 /* User wants to cancel this file and any
2018 * remaining in batch.
2019 */
2020 cip->errNo = kErrUserCanceled;
2021 return (cip->errNo);
2022 } else if (zaction == kConfirmResumeProcSaidSkip) {
2023 /* Nothing done, but not an error. */
2024 if (deleteflag == kDeleteYes)
2026 return (kNoErr);
2027 } else if (zaction == kConfirmResumeProcSaidResume) {
2028 /* Resume; proc set the startPoint. */
2029 if (startPoint == expectedSize) {
2030 /* Don't go to all the trouble of downloading nothing. */
2031 /* Nothing done, but not an error. */
2032 if (deleteflag == kDeleteYes)
2034 return (kNoErr);
2035 } else if (startPoint > expectedSize) {
2036 /* Cannot set start point past end of remote file */
2038 return (result);
2039 }
2040 fd = Open(dstfile, O_WRONLY|O_APPEND|O_BINARY, 00666);
2041 } else if (zaction == kConfirmResumeProcSaidAppend) {
2042 /* leave startPoint at zero, we will append everything. */
2043 startPoint = (longest_int) 0;
2044 fd = Open(dstfile, O_WRONLY|O_CREAT|O_APPEND|O_BINARY, 00666);
2045 } else /* if (zaction == kConfirmResumeProcSaidOverwrite) */ {
2046 created = 1;
2047 startPoint = (longest_int) 0;
2048 fd = Open(dstfile, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 00666);
2049 }
2050
2051 if (fd < 0) {
2052 Error(cip, kDoPerror, "Cannot open local file %s for writing.\n", dstfile);
2054 cip->errNo = kErrOpenFailed;
2055 return (result);
2056 }
2057
2058 if ((expectedSize == (longest_int) 0) && (startPoint <= (longest_int) 0) && (zaction != kConfirmResumeProcSaidOverwrite)) {
2059 /* Don't go to all the trouble of downloading nothing. */
2060#if defined(WIN32) || defined(_WINDOWS)
2061 /* Note: Windows doesn't allow zero-size files. */
2062 (void) write(fd, "\r\n", 2);
2063#endif
2064 (void) close(fd);
2065 if (mdtm != kModTimeUnknown) {
2066 cip->mdtm = mdtm;
2067 (void) time(&ut.actime);
2068 ut.modtime = mdtm;
2069 (void) utime(dstfile, &ut);
2070 }
2071 if (deleteflag == kDeleteYes)
2073 return (kNoErr);
2074 }
2075 } else {
2076 fd = fdtouse;
2077 }
2078
2079 if ((cip->numDownloads == 0) && (cip->dataSocketRBufSize > 0)) {
2080 /* If dataSocketSBufSize is non-zero, it means you
2081 * want to explicitly try to set the size of the
2082 * socket's I/O buffer.
2083 *
2084 * If it is zero, it means you want to just use the
2085 * TCP stack's default value, which is typically
2086 * between 8 and 64 kB.
2087 *
2088 * If you try to set the buffer larger than 64 kB,
2089 * the TCP stack should try to use RFC 1323 to
2090 * negotiate "TCP Large Windows" which may yield
2091 * significant performance gains.
2092 */
2094 (void) FTPCmd(cip, "SITE RETRBUFSIZE %lu", (unsigned long) cip->dataSocketRBufSize);
2095 else if (cip->hasRBUFSIZ == kCommandAvailable)
2096 (void) FTPCmd(cip, "SITE RBUFSIZ %lu", (unsigned long) cip->dataSocketRBufSize);
2097 else if (cip->hasRBUFSZ == kCommandAvailable)
2098 (void) FTPCmd(cip, "SITE RBUFSZ %lu", (unsigned long) cip->dataSocketRBufSize);
2099 else if (cip->hasBUFSIZE == kCommandAvailable)
2100 (void) FTPCmd(cip, "SITE BUFSIZE %lu", (unsigned long) cip->dataSocketSBufSize);
2101 }
2102
2103#ifdef NO_SIGNALS
2104#else /* NO_SIGNALS */
2105 vcip = cip;
2106 vfdtouse = fdtouse;
2107 vfd = fd;
2108 osigpipe = (volatile FTPSigProc) signal(SIGPIPE, BrokenData);
2109
2110 gGotBrokenData = 0;
2111 gCanBrokenDataJmp = 0;
2112
2113#ifdef HAVE_SIGSETJMP
2114 sj = sigsetjmp(gBrokenDataJmp, 1);
2115#else
2116 sj = setjmp(gBrokenDataJmp);
2117#endif /* HAVE_SIGSETJMP */
2118
2119 if (sj != 0) {
2120 (void) signal(SIGPIPE, (FTPSigProc) osigpipe);
2121 if (vfdtouse < 0) {
2122 (void) close(vfd);
2123 }
2124 FTPShutdownHost(vcip);
2126 return(vcip->errNo);
2127 }
2128 gCanBrokenDataJmp = 1;
2129#endif /* NO_SIGNALS */
2130
2131 tmpResult = FTPStartDataCmd(cip, kNetReading, xtype, startPoint, "RETR %s", file);
2132
2133 if (tmpResult < 0) {
2134 result = tmpResult;
2135 if (result == kErrGeneric)
2137 cip->errNo = result;
2138 if (fdtouse < 0) {
2139 (void) close(fd);
2140 if ((created != 0) && (appendflag == kAppendNo) && (cip->startPoint == 0))
2141 (void) unlink(dstfile);
2142 }
2143#if !defined(NO_SIGNALS)
2144 (void) signal(SIGPIPE, (FTPSigProc) osigpipe);
2145#endif /* NO_SIGNALS */
2146 return (result);
2147 }
2148
2149 if ((startPoint != 0) && (cip->startPoint == 0)) {
2150 /* Remote could not or would not set the start offset
2151 * to what we wanted.
2152 *
2153 * So now we have to undo our seek.
2154 */
2155 if (Lseek(fd, (off_t) 0, SEEK_SET) != (off_t) 0) {
2156 cip->errNo = kErrLseekFailed;
2157 if (fdtouse < 0) {
2158 (void) close(fd);
2159 }
2160#if !defined(NO_SIGNALS)
2161 (void) signal(SIGPIPE, (FTPSigProc) osigpipe);
2162#endif /* NO_SIGNALS */
2163 return (cip->errNo);
2164 }
2165 startPoint = 0;
2166 }
2167
2168 buf = cip->buf;
2169 bufSize = cip->bufSize;
2170
2171 FTPInitIOTimer(cip);
2172 cip->mdtm = mdtm;
2173 (void) time(&ut.actime);
2174 ut.modtime = mdtm;
2175 cip->expectedSize = expectedSize;
2176 cip->lname = dstfile; /* could be NULL */
2177 cip->rname = file;
2178 if (fdtouse >= 0)
2179 cip->useProgressMeter = 0;
2180 FTPStartIOTimer(cip);
2181
2182#if ASCII_TRANSLATION
2183 if (xtype == kTypeAscii) {
2184 /* Ascii */
2185 for (;;) {
2186 if (! WaitForRemoteInput(cip)) { /* could set cancelXfer */
2187 cip->errNo = result = kErrDataTimedOut;
2188 Error(cip, kDontPerror, "Remote read timed out.\n");
2189 break;
2190 }
2191 if (cip->cancelXfer > 0) {
2194 break;
2195 }
2196#ifdef TESTING_ABOR
2197 if (cip->bytesTransferred > 0) {
2198 cip->cancelXfer = 1;
2201 break;
2202 }
2203#endif /* TESTING_ABOR */
2204#ifdef NO_SIGNALS
2206 if (nread == kTimeoutErr) {
2207 cip->errNo = result = kErrDataTimedOut;
2208 Error(cip, kDontPerror, "Remote read timed out.\n");
2209 break;
2210 } else if (nread < 0) {
2211 if ((gGotBrokenData != 0) || (errno == EPIPE)) {
2213 errno = EPIPE;
2214 Error(cip, kDoPerror, "Lost data connection to remote host.\n");
2215 } else if (errno == EINTR) {
2216 continue;
2217 } else {
2218 Error(cip, kDoPerror, "Remote read failed.\n");
2221 }
2222 break;
2223 } else if (nread == 0) {
2224 break;
2225 }
2226#else
2227 gCanBrokenDataJmp = 1;
2228 if (cip->xferTimeout > 0)
2229 (void) alarm(cip->xferTimeout);
2230 nread = read(cip->dataSocket, buf, bufSize);
2231 if (nread < 0) {
2232 if ((gGotBrokenData != 0) || (errno == EPIPE)) {
2234 errno = EPIPE;
2235 Error(cip, kDoPerror, "Lost data connection to remote host.\n");
2236 (void) shutdown(cip->dataSocket, 2);
2237 } else if (errno == EINTR) {
2238 continue;
2239 } else {
2241 Error(cip, kDoPerror, "Remote read failed.\n");
2242 (void) shutdown(cip->dataSocket, 2);
2243 }
2244 break;
2245 } else if (nread == 0) {
2246 break;
2247 }
2248
2249 gCanBrokenDataJmp = 0;
2250#endif /* NO_SIGNALS */
2251
2252 src = buf;
2253 srclim = src + nread;
2254 dst = outbuf;
2255 dstlim = dst + sizeof(outbuf);
2256 while (src < srclim) {
2257 if (*src == '\r') {
2258 src++;
2259 continue;
2260 }
2261 if (dst >= dstlim) {
2262 nwrote = write(fd, outbuf, (size_t) (dst - outbuf));
2263 if (nwrote == (int) (dst - outbuf)) {
2264 /* Success. */
2265 dst = outbuf;
2266 } else if ((gGotBrokenData != 0) || (errno == EPIPE)) {
2268 cip->errNo = kErrWriteFailed;
2269 errno = EPIPE;
2270 (void) shutdown(cip->dataSocket, 2);
2271 goto brk;
2272 } else {
2273 Error(cip, kDoPerror, "Local write failed.\n");
2275 cip->errNo = kErrWriteFailed;
2276 (void) shutdown(cip->dataSocket, 2);
2277 goto brk;
2278 }
2279 }
2280 *dst++ = *src++;
2281 }
2282 if (dst > outbuf) {
2283 nwrote = write(fd, outbuf, (size_t) (dst - outbuf));
2284 if (nwrote != (int) (dst - outbuf)) {
2285 if ((gGotBrokenData != 0) || (errno == EPIPE)) {
2287 cip->errNo = kErrWriteFailed;
2288 errno = EPIPE;
2289 (void) shutdown(cip->dataSocket, 2);
2290 goto brk;
2291 } else {
2292 Error(cip, kDoPerror, "Local write failed.\n");
2294 cip->errNo = kErrWriteFailed;
2295 (void) shutdown(cip->dataSocket, 2);
2296 goto brk;
2297 }
2298 }
2299 }
2300
2301 if (mdtm != kModTimeUnknown) {
2302 (void) utime(dstfile, &ut);
2303 }
2304 cip->bytesTransferred += (longest_int) nread;
2305 FTPUpdateIOTimer(cip);
2306 }
2307 } else
2308#endif /* ASCII_TRANSLATION */
2309 {
2310 /* Binary */
2311 for (;;) {
2312 if (! WaitForRemoteInput(cip)) { /* could set cancelXfer */
2313 cip->errNo = result = kErrDataTimedOut;
2314 Error(cip, kDontPerror, "Remote read timed out.\n");
2315 break;
2316 }
2317 if (cip->cancelXfer > 0) {
2320 break;
2321 }
2322#ifdef TESTING_ABOR
2323 if (cip->bytesTransferred > 0) {
2324 cip->cancelXfer = 1;
2327 break;
2328 }
2329#endif /* TESTING_ABOR */
2330#ifdef NO_SIGNALS
2332 if (nread == kTimeoutErr) {
2333 cip->errNo = result = kErrDataTimedOut;
2334 Error(cip, kDontPerror, "Remote read timed out.\n");
2335 break;
2336 } else if (nread < 0) {
2337 if ((gGotBrokenData != 0) || (errno == EPIPE)) {
2339 errno = EPIPE;
2340 Error(cip, kDoPerror, "Lost data connection to remote host.\n");
2341 } else if (errno == EINTR) {
2342 continue;
2343 } else {
2344 Error(cip, kDoPerror, "Remote read failed.\n");
2347 }
2348 break;
2349 } else if (nread == 0) {
2350 break;
2351 }
2352#else
2353 gCanBrokenDataJmp = 1;
2354 if (cip->xferTimeout > 0)
2355 (void) alarm(cip->xferTimeout);
2356 nread = read(cip->dataSocket, buf, bufSize);
2357 if (nread < 0) {
2358 if ((gGotBrokenData != 0) || (errno == EPIPE)) {
2360 errno = EPIPE;
2361 Error(cip, kDoPerror, "Lost data connection to remote host.\n");
2362 } else if (errno == EINTR) {
2363 continue;
2364 } else {
2366 Error(cip, kDoPerror, "Remote read failed.\n");
2367 }
2368 (void) shutdown(cip->dataSocket, 2);
2369 break;
2370 } else if (nread == 0) {
2371 break;
2372 }
2373 gCanBrokenDataJmp = 0;
2374#endif /* NO_SIGNALS */
2375
2376 nwrote = write(fd, buf, nread);
2377 if (nwrote != nread) {
2378 if ((gGotBrokenData != 0) || (errno == EPIPE)) {
2380 cip->errNo = kErrWriteFailed;
2381 errno = EPIPE;
2382 } else {
2383 Error(cip, kDoPerror, "Local write failed.\n");
2385 cip->errNo = kErrWriteFailed;
2386 }
2387 (void) shutdown(cip->dataSocket, 2);
2388 break;
2389 }
2390
2391 /* Ugggh... do this after each write operation
2392 * so it minimizes the chance of a user killing
2393 * the process before we reset the timestamps.
2394 */
2395 if (mdtm != kModTimeUnknown) {
2396 (void) utime(dstfile, &ut);
2397 }
2398 cip->bytesTransferred += (longest_int) nread;
2399 FTPUpdateIOTimer(cip);
2400 }
2401 }
2402
2403#if ASCII_TRANSLATION
2404brk:
2405#endif
2406
2407#if !defined(NO_SIGNALS)
2408 if (cip->xferTimeout > 0)
2409 (void) alarm(0);
2410 gCanBrokenDataJmp = 0;
2411#endif /* NO_SIGNALS */
2412
2413 if (fdtouse < 0) {
2414 /* If they gave us a descriptor (fdtouse >= 0),
2415 * leave it open, otherwise we opened it, so
2416 * we need to close it.
2417 */
2418 (void) close(fd);
2419 fd = -1;
2420 }
2421
2422 tmpResult = FTPEndDataCmd(cip, 1);
2423 if ((tmpResult < 0) && (result == 0)) {
2425 cip->errNo = kErrRETRFailed;
2426 }
2427 FTPStopIOTimer(cip);
2428#if !defined(NO_SIGNALS)
2429 (void) signal(SIGPIPE, (FTPSigProc) osigpipe);
2430#endif /* NO_SIGNALS */
2431
2432 if ((mdtm != kModTimeUnknown) && (cip->bytesTransferred > 0)) {
2433 (void) utime(dstfile, &ut);
2434 }
2435
2436 if (result == kNoErr) {
2437 cip->numDownloads++;
2438
2439 if (deleteflag == kDeleteYes) {
2441 }
2442 }
2443
2444 return (result);
2445} /* FTPGetOneF */
2446
2447
2448
2449
2450int
2452 const FTPCIPtr cip,
2453 const char *const file,
2454 const char *const dstfile,
2455 const int xtype,
2456 const int fdtouse,
2457 const int resumeflag,
2458 const int appendflag,
2459 const int deleteflag,
2460 const ConfirmResumeDownloadProc resumeProc,
2461 int UNUSED(reserved))
2462{
2463 int result;
2464
2466 if (cip == NULL)
2467 return (kErrBadParameter);
2468 if (strcmp(cip->magic, kLibraryMagic))
2469 return (kErrBadMagic);
2470
2471 if ((file == NULL) || (file[0] == '\0'))
2472 return (kErrBadParameter);
2473 if (fdtouse < 0) {
2474 if ((dstfile == NULL) || (dstfile[0] == '\0'))
2475 return (kErrBadParameter);
2476 }
2477
2478 result = FTPGetOneF(cip, file, dstfile, xtype, fdtouse, kSizeUnknown, kModTimeUnknown, resumeflag, appendflag, deleteflag, resumeProc);
2479 return (result);
2480} /* FTPGetOneFile3 */
2481
2482
2483
2484
2485int
2487 const FTPCIPtr cip,
2488 const char *pattern1,
2489 const char *const dstdir1,
2490 const int recurse,
2491 int doGlob,
2492 const int xtype,
2493 const int resumeflag,
2494 int appendflag,
2495 const int deleteflag,
2496 const int tarflag,
2497 const ConfirmResumeDownloadProc resumeProc,
2498 int UNUSED(reserved))
2499{
2500 LineList globList;
2501 LinePtr itemPtr;
2502 FileInfoList files;
2503 FileInfoPtr filePtr;
2504 int batchResult;
2505 int result;
2506 char *ldir;
2507 char *cp;
2508 const char *dstdir;
2509 const char *pattern;
2510 char *pattern2, *dstdir2;
2511 char c;
2512 int recurse1;
2513 int errRc;
2514
2516 if (cip == NULL)
2517 return (kErrBadParameter);
2518 if (strcmp(cip->magic, kLibraryMagic))
2519 return (kErrBadMagic);
2520 if (pattern1 == NULL)
2521 return (kErrBadParameter);
2522
2523 dstdir2 = NULL;
2524 pattern2 = NULL;
2525
2526 if (dstdir1 == NULL) {
2527 dstdir = NULL;
2528 } else {
2529 dstdir2 = StrDup(dstdir1);
2530 if (dstdir2 == NULL) {
2531 errRc = kErrMallocFailed;
2532 goto return_err;
2533 }
2535 dstdir = dstdir2;
2536 }
2537
2538 pattern2 = StrDup(pattern1);
2539 if (pattern2 == NULL) {
2540 errRc = kErrMallocFailed;
2541 goto return_err;
2542 }
2543 StrRemoveTrailingSlashes(pattern2);
2544 pattern = pattern2;
2545
2546 if (pattern[0] == '\0') {
2547 if (recurse == kRecursiveNo) {
2548 errRc = kErrBadParameter;
2549 goto return_err;
2550 }
2551 pattern = ".";
2552 doGlob = kGlobNo;
2553 } else if (strcmp(pattern, ".") == 0) {
2554 if (recurse == kRecursiveNo) {
2555 errRc = kErrBadParameter;
2556 goto return_err;
2557 }
2558 doGlob = kGlobNo;
2559 }
2560 if (recurse == kRecursiveYes)
2561 appendflag = kAppendNo;
2562
2563 batchResult = FTPRemoteGlob(cip, &globList, pattern, doGlob);
2564 if (batchResult != kNoErr) {
2565 errRc = batchResult;
2566 goto return_err;
2567 }
2568
2569 cip->cancelXfer = 0; /* should already be zero */
2570
2571 for (itemPtr = globList.first; itemPtr != NULL; itemPtr = itemPtr->next) {
2572 if ((recurse == kRecursiveYes) && (FTPIsDir(cip, itemPtr->line) > 0)) {
2573#ifdef TAR
2574 if ((tarflag == kTarYes) && (xtype == kTypeBinary) && (appendflag == kAppendNo) && (deleteflag == kDeleteNo) && (FTPGetOneTarF(cip, itemPtr->line, dstdir) == kNoErr)) {
2575 /* Great! */
2576 continue;
2577 }
2578#endif /* TAR */
2579 (void) FTPRemoteRecursiveFileList1(cip, itemPtr->line, &files);
2580 (void) ComputeLNames(&files, itemPtr->line, dstdir, 1);
2581 recurse1 = recurse;
2582 } else {
2583 recurse1 = kRecursiveNo;
2584 (void) LineToFileInfoList(itemPtr, &files);
2585 (void) ComputeRNames(&files, ".", 0, 1);
2586 (void) ComputeLNames(&files, NULL, dstdir, 0);
2587 }
2588 if (cip->cancelXfer > 0) {
2590 break;
2591 }
2592
2593#if 0
2594 for (filePtr = files.first; filePtr != NULL; filePtr = filePtr->next) {
2595 PrintF(cip, " R=%s, L=%s, 2=%s, size=%d, mdtm=%u, type=%c\n",
2596 filePtr->rname,
2597 filePtr->lname,
2598 filePtr->rlinkto ? filePtr->rlinkto : "",
2599 filePtr->size,
2600 (unsigned int) filePtr->mdtm,
2601 filePtr->type
2602 );
2603 }
2604#endif
2605
2606
2607 for (filePtr = files.first; filePtr != NULL; filePtr = filePtr->next) {
2608 if (cip->connected == 0) {
2609 if (batchResult == kNoErr)
2610 batchResult = kErrRemoteHostClosedConnection;
2611 break;
2612 }
2613 if (filePtr->type == 'd') {
2614#if defined(WIN32) || defined(_WINDOWS)
2615 (void) MkDirs(filePtr->lname, 00777);
2616#else
2617 (void) mkdir(filePtr->lname, 00777);
2618#endif
2619 } else if (filePtr->type == 'l') {
2620 /* skip it -- we do that next pass. */
2621 } else if (recurse1 != kRecursiveYes) {
2622 result = FTPGetOneF(cip, filePtr->rname, filePtr->lname, xtype, -1, filePtr->size, filePtr->mdtm, resumeflag, appendflag, deleteflag, resumeProc);
2623 if (files.nFileInfos == 1) {
2624 if (result != kNoErr)
2625 batchResult = result;
2626 } else {
2628 batchResult = result;
2629 }
2630 if (result == kErrUserCanceled)
2631 cip->cancelXfer = 1;
2632 if (cip->cancelXfer > 0)
2633 break;
2634 } else {
2635 ldir = filePtr->lname;
2636 cp = StrRFindLocalPathDelim(ldir);
2637 if (cp != NULL) {
2638 while (cp > ldir) {
2639 if (! IsLocalPathDelim(*cp)) {
2640 ++cp;
2641 break;
2642 }
2643 --cp;
2644 }
2645 if (cp > ldir) {
2646 c = *cp;
2647 *cp = '\0';
2648 if (MkDirs(ldir, 00777) < 0) {
2649 Error(cip, kDoPerror, "Could not create local directory \"%s\"\n", ldir);
2650 batchResult = kErrGeneric;
2651 *cp = c;
2652 continue;
2653 }
2654 *cp = c;
2655 }
2656 }
2657 result = FTPGetOneF(cip, filePtr->rname, filePtr->lname, xtype, -1, filePtr->size, filePtr->mdtm, resumeflag, appendflag, deleteflag, resumeProc);
2658
2659 if (files.nFileInfos == 1) {
2660 if (result != kNoErr)
2661 batchResult = result;
2662 } else {
2664 batchResult = result;
2665 }
2666 if (result == kErrUserCanceled)
2667 cip->cancelXfer = 1;
2668 if (cip->cancelXfer > 0)
2669 break;
2670 }
2671 }
2672 if (cip->cancelXfer > 0) {
2674 break;
2675 }
2676
2677#ifdef HAVE_SYMLINK
2678 for (filePtr = files.first; filePtr != NULL; filePtr = filePtr->next) {
2679 if (filePtr->type == 'l') {
2680 (void) unlink(filePtr->lname);
2681 if (symlink(filePtr->rlinkto, filePtr->lname) < 0) {
2682 Error(cip, kDoPerror, "Could not symlink %s to %s\n", filePtr->rlinkto, filePtr->lname);
2683 /* Note: not worth setting batchResult */
2684 }
2685 }
2686 }
2687#endif /* HAVE_SYMLINK */
2688
2689
2691 }
2692
2693 DisposeLineListContents(&globList);
2694 if (batchResult < 0)
2695 cip->errNo = batchResult;
2696 errRc = batchResult;
2697
2698return_err:
2699 if (dstdir2 != NULL)
2700 free(dstdir2);
2701 if (pattern2 != NULL)
2702 free(pattern2);
2703 return (errRc);
2704} /* FTPGetFiles3 */
2705
2706
2707
2708
2709/*------------------------- wrappers for old routines ----------------------*/
2710
2711int
2712FTPGetOneFile(const FTPCIPtr cip, const char *const file, const char *const dstfile)
2713{
2715} /* FTPGetOneFile */
2716
2717
2718
2719
2720int
2721FTPGetOneFile2(const FTPCIPtr cip, const char *const file, const char *const dstfile, const int xtype, const int fdtouse, const int resumeflag, const int appendflag)
2722{
2723 return (FTPGetOneFile3(cip, file, dstfile, xtype, fdtouse, resumeflag, appendflag, kDeleteNo, (ConfirmResumeDownloadProc) 0, 0));
2724} /* FTPGetOneFile2 */
2725
2726
2727
2728
2729int
2730FTPGetFiles(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob)
2731{
2732 return (FTPGetFiles3(cip, pattern, dstdir, recurse, doGlob, kTypeBinary, kResumeNo, kAppendNo, kDeleteNo, kTarYes, (ConfirmResumeDownloadProc) 0, 0));
2733} /* FTPGetFiles */
2734
2735
2736
2737
2738int
2739FTPGetFiles2(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob, const int xtype, const int resumeflag, const int appendflag)
2740{
2741 return (FTPGetFiles3(cip, pattern, dstdir, recurse, doGlob, xtype, resumeflag, appendflag, kDeleteNo, kTarYes, (ConfirmResumeDownloadProc) 0, 0));
2742} /* FTPGetFiles2 */
2743
2744
2745
2746
2747int
2748FTPGetOneFileAscii(const FTPCIPtr cip, const char *const file, const char *const dstfile)
2749{
2751} /* FTPGetOneFileAscii */
2752
2753
2754
2755
2756int
2757FTPGetFilesAscii(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob)
2758{
2759 return (FTPGetFiles3(cip, pattern, dstdir, recurse, doGlob, kTypeAscii, kResumeNo, kAppendNo, kDeleteNo, kTarNo, (ConfirmResumeDownloadProc) 0, 0));
2760} /* FTPGetFilesAscii */
2761
2762
2763
2764
2765int
2766FTPPutOneFile(const FTPCIPtr cip, const char *const file, const char *const dstfile)
2767{
2768 return (FTPPutOneFile3(cip, file, dstfile, kTypeBinary, -1, 0, NULL, NULL, kResumeNo, kDeleteNo, NoConfirmResumeUploadProc, 0));
2769} /* FTPPutOneFile */
2770
2771
2772
2773
2774int
2775FTPPutOneFile2(const FTPCIPtr cip, const char *const file, const char *const dstfile, const int xtype, const int fdtouse, const int appendflag, const char *const tmppfx, const char *const tmpsfx)
2776{
2777 return (FTPPutOneFile3(cip, file, dstfile, xtype, fdtouse, appendflag, tmppfx, tmpsfx, kResumeNo, kDeleteNo, NoConfirmResumeUploadProc, 0));
2778} /* FTPPutOneFile2 */
2779
2780
2781
2782
2783int
2784FTPPutFiles(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob)
2785{
2786 return (FTPPutFiles3(cip, pattern, dstdir, recurse, doGlob, kTypeBinary, 0, NULL, NULL, kResumeNo, kDeleteNo, NoConfirmResumeUploadProc, 0));
2787} /* FTPPutFiles */
2788
2789
2790
2791
2792int
2793FTPPutFiles2(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob, const int xtype, const int appendflag, const char *const tmppfx, const char *const tmpsfx)
2794{
2795 return (FTPPutFiles3(cip, pattern, dstdir, recurse, doGlob, xtype, appendflag, tmppfx, tmpsfx, kResumeNo, kDeleteNo, NoConfirmResumeUploadProc, 0));
2796} /* FTPPutFiles2 */
2797
2798
2799
2800
2801int
2802FTPPutOneFileAscii(const FTPCIPtr cip, const char *const file, const char *const dstfile)
2803{
2804 return (FTPPutOneFile3(cip, file, dstfile, kTypeAscii, -1, 0, NULL, NULL, kResumeNo, kDeleteNo, NoConfirmResumeUploadProc, 0));
2805} /* FTPPutOneFileAscii */
2806
2807
2808
2809
2810int
2811FTPPutFilesAscii(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob)
2812{
2813 return (FTPPutFiles3(cip, pattern, dstdir, recurse, doGlob, kTypeAscii, 0, NULL, NULL, kResumeNo, kDeleteNo, NoConfirmResumeUploadProc, 0));
2814} /* FTPPutFilesAscii */
2815
2816
2817
2818int
2819FTPListToMemory(const FTPCIPtr cip, const char *const pattern, const LineListPtr llines, const char *const lsflags)
2820{
2821 return (FTPListToMemory2(cip, pattern, llines, lsflags, 1, (int *) 0));
2822} /* FTPListToMemory */
2823
2824/* eof IO.c */
#define STRNCAT(d, s)
Definition: Strn.h:48
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
#define EINTR
Definition: acclib.h:80
#define EPIPE
Definition: acclib.h:91
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
char * strchr(const char *String, int ch)
Definition: utclib.c:501
#define O_WRONLY
Definition: acwin.h:111
#define O_CREAT
Definition: acwin.h:110
#define mkdir
Definition: acwin.h:101
#define read
Definition: acwin.h:96
#define O_RDONLY
Definition: acwin.h:108
#define close
Definition: acwin.h:98
#define write
Definition: acwin.h:97
#define O_TRUNC
Definition: acwin.h:112
#define gettimeofday(tv, tz)
Definition: adns_win32.h:159
static int inbuf
Definition: adnsresfilter.c:73
#define STRNCPY(dst, src, n)
Definition: rdesktop.h:168
#define S_ISDIR(mode)
Definition: various.h:18
#define S_ISREG(mode)
Definition: various.h:17
BOOL Error
Definition: chkdsk.c:66
#define UNUSED(x)
Definition: btrfs_drv.h:82
r l[0]
Definition: byte_order.h:168
#define setjmp
Definition: setjmp.h:209
_JBTYPE jmp_buf[_JBLEN]
Definition: setjmp.h:186
#define SIGPIPE
Definition: signal.h:35
#define SIG_IGN
Definition: signal.h:48
#define free
Definition: debug_ros.c:5
#define NULL
Definition: types.h:112
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
INT WSAAPI select(IN INT s, IN OUT LPFD_SET readfds, IN OUT LPFD_SET writefds, IN OUT LPFD_SET exceptfds, IN CONST struct timeval *timeout)
Definition: select.c:41
r reserved
Definition: btrfs.c:3006
__kernel_size_t size_t
Definition: linux.h:237
__kernel_time_t time_t
Definition: linux.h:252
__kernel_off_t off_t
Definition: linux.h:201
time_t now
Definition: finger.c:65
#define utime
Definition: getline.c:47
GLenum src
Definition: glext.h:6340
const GLubyte * c
Definition: glext.h:8905
GLubyte * pattern
Definition: glext.h:7787
GLfloat f
Definition: glext.h:7540
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLenum GLenum dst
Definition: glext.h:6340
GLuint GLint GLboolean GLint GLenum access
Definition: glext.h:7866
GLuint GLsizei bufSize
Definition: glext.h:6040
GLuint64EXT * result
Definition: glext.h:11304
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
int FTPLocalRecursiveFileList(FTPCIPtr cip, LineListPtr fileList, FileInfoListPtr files)
Definition: glob.c:1333
int FTPRemoteRecursiveFileList1(FTPCIPtr cip, char *const rdir, FileInfoListPtr files)
Definition: glob.c:983
int FTPLocalGlob(FTPCIPtr cip, LineListPtr fileList, const char *pattern, int doGlob)
Definition: glob.c:1580
int FTPRemoteGlob(FTPCIPtr cip, LineListPtr fileList, const char *pattern, int doGlob)
Definition: glob.c:1341
#define ss
Definition: i386-dis.c:441
_Check_return_ _CRTIMP int __cdecl iscntrl(_In_ int _C)
#define O_APPEND
Definition: fcntl.h:37
_CRTIMP void __cdecl perror(_In_opt_z_ const char *_ErrMsg)
#define SEEK_SET
Definition: jmemansi.c:26
#define f
Definition: ke_i.h:83
#define c
Definition: ke_i.h:80
#define unlink
Definition: syshdrs.h:54
#define Lseek(a, b, c)
Definition: syshdrs.h:96
#define Stat
Definition: syshdrs.h:78
#define Fstat
Definition: syshdrs.h:79
#define Open
Definition: syshdrs.h:62
#define SELECT_TYPE_ARG234
Definition: wincfg.h:4
int ComputeLNames(FileInfoListPtr dst, const char *srcdir, const char *dstdir, int nochop)
Definition: linelist.c:663
void InitLineList(LineListPtr list)
Definition: linelist.c:54
int ComputeRNames(FileInfoListPtr dst, const char *dstdir, int pflag, int nochop)
Definition: linelist.c:579
int LineToFileInfoList(LinePtr lp, FileInfoListPtr dst)
Definition: linelist.c:775
void DisposeFileInfoListContents(FileInfoListPtr list)
Definition: linelist.c:152
int LineListToFileInfoList(LineListPtr src, FileInfoListPtr dst)
Definition: linelist.c:758
void DisposeLineListContents(LineListPtr list)
Definition: linelist.c:33
LinePtr AddLine(LineListPtr list, const char *buf1)
Definition: linelist.c:94
if(dx< 0)
Definition: linetemp.h:194
POINT cp
Definition: magnifier.c:59
__u16 time
Definition: mkdosfs.c:8
int FTPSymlink(const FTPCIPtr cip, const char *const lfrom, const char *const lto)
Definition: cmds.c:1585
int FTPFileSizeAndModificationTime(const FTPCIPtr cip, const char *const file, longest_int *const size, const int type, time_t *const mdtm)
Definition: cmds.c:1433
int FTPMkdir(const FTPCIPtr cip, const char *const newDir, const int recurse)
Definition: cmds.c:641
int FTPUtime(const FTPCIPtr cip, const char *const file, time_t actime, time_t modtime, time_t crtime)
Definition: cmds.c:1649
int FTPFileModificationTime(const FTPCIPtr cip, const char *const file, time_t *const mdtm)
Definition: cmds.c:649
int FTPFileExists2(const FTPCIPtr cip, const char *const file, const int tryMDTM, const int trySIZE, const int tryMLST, const int trySTAT, const int tryNLST)
Definition: cmds.c:1350
int FTPDelete(const FTPCIPtr cip, const char *const pattern, const int recurse, const int doGlob)
Definition: cmds.c:195
int FTPGetCWD(const FTPCIPtr cip, char *const newCwd, const size_t newCwdSize)
Definition: cmds.c:254
int FTPRename(const FTPCIPtr cip, const char *const oldname, const char *const newname)
Definition: cmds.c:703
int FTPIsDir(const FTPCIPtr cip, const char *const dir)
Definition: cmds.c:1531
int FTPChdir(const FTPCIPtr cip, const char *const cdCwd)
Definition: cmds.c:11
int FTPSetTransferType(const FTPCIPtr cip, int type)
Definition: cmds.c:836
const char * FTPStrError(int e)
Definition: errno.c:114
int SetStartOffset(const FTPCIPtr cip, longest_int restartPt)
Definition: ftp.c:853
int FTPPutFiles2(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob, const int xtype, const int appendflag, const char *const tmppfx, const char *const tmpsfx)
Definition: io.c:2793
int FTPGetFiles2(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob, const int xtype, const int resumeflag, const int appendflag)
Definition: io.c:2739
int FTPPutFilesAscii(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob)
Definition: io.c:2811
int FTPPutFiles(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob)
Definition: io.c:2784
int FTPListToMemory(const FTPCIPtr cip, const char *const pattern, const LineListPtr llines, const char *const lsflags)
Definition: io.c:2819
static int WaitForRemoteInput(const FTPCIPtr cip)
Definition: io.c:1424
int FTPGetFiles3(const FTPCIPtr cip, const char *pattern1, const char *const dstdir1, const int recurse, int doGlob, const int xtype, const int resumeflag, int appendflag, const int deleteflag, const int tarflag, const ConfirmResumeDownloadProc resumeProc, int UNUSED(reserved))
Definition: io.c:2486
int FTPListToMemory2(const FTPCIPtr cip, const char *const pattern, const LineListPtr llines, const char *const lsflags, const int blankLines, int *const tryMLSD)
Definition: io.c:366
#define O_BINARY
Definition: io.c:41
int FTPGetOneFileAscii(const FTPCIPtr cip, const char *const file, const char *const dstfile)
Definition: io.c:2748
static int WaitForRemoteOutput(const FTPCIPtr cip)
Definition: io.c:585
void FTPInitIOTimer(const FTPCIPtr cip)
Definition: io.c:71
int FTPGetFiles(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob)
Definition: io.c:2730
static int FTPPutOneF(const FTPCIPtr cip, const char *const file, const char *volatile dstfile, int xtype, const int fdtouse, const int appendflag, const char *volatile tmppfx, const char *volatile tmpsfx, const int resumeflag, const int deleteflag, const ConfirmResumeUploadProc resumeProc)
Definition: io.c:650
int FTPPutOneFile2(const FTPCIPtr cip, const char *const file, const char *const dstfile, const int xtype, const int fdtouse, const int appendflag, const char *const tmppfx, const char *const tmpsfx)
Definition: io.c:2775
int FTPGetFilesAscii(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob)
Definition: io.c:2757
int FTPGetOneFile3(const FTPCIPtr cip, const char *const file, const char *const dstfile, const int xtype, const int fdtouse, const int resumeflag, const int appendflag, const int deleteflag, const ConfirmResumeDownloadProc resumeProc, int UNUSED(reserved))
Definition: io.c:2451
int FTPPutOneFile(const FTPCIPtr cip, const char *const file, const char *const dstfile)
Definition: io.c:2766
static void FTPRequestMlsOptions(const FTPCIPtr cip)
Definition: io.c:289
static int FTPGetOneF(const FTPCIPtr cip, const char *const file, const char *dstfile, int xtype, const int fdtouse, longest_int expectedSize, time_t mdtm, const int resumeflag, const int appendflag, const int deleteflag, const ConfirmResumeDownloadProc resumeProc)
Definition: io.c:1817
void FTPStartIOTimer(const FTPCIPtr cip)
Definition: io.c:93
static int gGotBrokenData
Definition: io.c:10
int FTPPutFiles3(const FTPCIPtr cip, const char *const pattern, const char *const dstdir1, const int recurse, const int doGlob, const int xtype, int appendflag, const char *const tmppfx, const char *const tmpsfx, const int resumeflag, const int deleteflag, const ConfirmResumeUploadProc resumeProc, int UNUSED(reserved))
Definition: io.c:1298
static void AutomaticallyUseASCIIModeDependingOnExtension(const FTPCIPtr cip, const char *const pathName, int *const xtype)
Definition: io.c:565
void FTPUpdateIOTimer(const FTPCIPtr cip)
Definition: io.c:104
int FTPPutOneFileAscii(const FTPCIPtr cip, const char *const file, const char *const dstfile)
Definition: io.c:2802
int FTPPutOneFile3(const FTPCIPtr cip, const char *const file, const char *const dstfile, const int xtype, const int fdtouse, const int appendflag, const char *const tmppfx, const char *const tmpsfx, const int resumeflag, const int deleteflag, const ConfirmResumeUploadProc resumeProc, int UNUSED(reserved))
Definition: io.c:1262
int FTPList(const FTPCIPtr cip, const int outfd, const int longMode, const char *const lsflag)
Definition: io.c:174
int FTPGetOneFile2(const FTPCIPtr cip, const char *const file, const char *const dstfile, const int xtype, const int fdtouse, const int resumeflag, const int appendflag)
Definition: io.c:2721
int FTPGetOneFile(const FTPCIPtr cip, const char *const file, const char *const dstfile)
Definition: io.c:2712
void FTPStopIOTimer(const FTPCIPtr cip)
Definition: io.c:159
void PrintF(const FTPCIPtr cip, const char *const fmt,...)
Definition: util.c:340
#define kDoPerror
Definition: util.h:44
#define kDontPerror
Definition: util.h:45
#define kNoFirstSelect
Definition: sio.h:52
int SWrite(int, const char *const, size_t, int, int)
Definition: SWrite.c:90
void DisposeSReadlineInfo(SReadlineInfo *)
Definition: SReadline.c:57
#define kFullBufferNotRequired
Definition: sio.h:49
int SReadline(SReadlineInfo *, char *const, size_t)
Definition: SReadline.c:76
int InitSReadlineInfo(SReadlineInfo *, int, char *, size_t, int, int)
Definition: SReadline.c:24
int SRead(int, char *const, size_t, int, int)
Definition: SRead.c:118
#define kTimeoutErr
Definition: sio.h:58
static const char mbstate_t *static wchar_t const char mbstate_t *static const wchar_t int *static double
Definition: string.c:80
int sigsetjmp(sigjmp_buf buf, int savesigs)
void siglongjmp(sigjmp_buf buf, int val)
jmp_buf sigjmp_buf
Definition: port.h:324
#define argv
Definition: mplay32.c:18
#define chdir
Definition: syshdrs.h:69
#define kGlobNo
Definition: ncftp.h:361
int FTPCmd(const FTPCIPtr cip, const char *const cmdspec,...)
Definition: rcmd.c:603
#define kNetReading
Definition: ncftp.h:303
#define kTarNo
Definition: ncftp.h:371
#define NoConfirmResumeUploadProc
Definition: ncftp.h:452
#define kMlsOptUNIXgid
Definition: ncftp.h:409
#define kResumeYes
Definition: ncftp.h:366
int BufferGets(char *, size_t, int, char *, char **, char **, size_t)
Definition: rcmd.c:978
void FTPShutdownHost(const FTPCIPtr cip)
Definition: open.c:564
#define kMlsOptUnique
Definition: ncftp.h:410
#define StrRFindLocalPathDelim(a)
Definition: ncftp.h:495
#define kConfirmResumeProcSaidOverwrite
Definition: ncftp.h:426
#define kTypeAscii
Definition: ncftp.h:353
#define kMlsOptSize
Definition: ncftp.h:402
#define kDeleteNo
Definition: ncftp.h:369
void(* FTPSigProc)(int)
Definition: ncftp.h:76
#define kTarYes
Definition: ncftp.h:370
#define kMlsOptModify
Definition: ncftp.h:403
#define kAppendNo
Definition: ncftp.h:365
#define kSizeUnknown
Definition: ncftp.h:376
int FTPEndDataCmd(const FTPCIPtr, int)
Definition: rcmd.c:933
int MkDirs(const char *const, int mode1)
Definition: util.c:785
#define kCommandAvailable
Definition: ncftp.h:380
#define kConfirmResumeProcSaidBestGuess
Definition: ncftp.h:428
int(* ConfirmResumeDownloadProc)(const char *volatile *localpath, volatile longest_int localsize, volatile time_t localmtime, const char *volatile remotepath, volatile longest_int remotesize, volatile time_t remotetime, volatile longest_int *volatile startPoint)
Definition: ncftp.h:431
#define kPrInitMsg
Definition: ncftp.h:290
#define kModTimeUnknown
Definition: ncftp.h:377
#define longest_int
Definition: ncftp.h:68
int FilenameExtensionIndicatesASCII(const char *const pathName, const char *const extnList)
Definition: util.c:963
#define kConfirmResumeProcSaidSkip
Definition: ncftp.h:424
#define kMlsOptType
Definition: ncftp.h:401
#define kPrEndMsg
Definition: ncftp.h:292
void FTPAbortDataTransfer(const FTPCIPtr cip)
Definition: rcmd.c:870
#define kPrUpdateMsg
Definition: ncftp.h:291
#define NoConfirmResumeDownloadProc
Definition: ncftp.h:451
#define kResumeNo
Definition: ncftp.h:367
#define kConfirmResumeProcSaidResume
Definition: ncftp.h:425
#define StrRemoveTrailingLocalPathDelim
Definition: ncftp.h:496
#define kMlsOptUNIXgroup
Definition: ncftp.h:406
int FTPStartDataCmd(const FTPCIPtr, int, int, longest_int, const char *,...)
Definition: rcmd.c:763
#define kConfirmResumeProcSaidCancel
Definition: ncftp.h:429
#define kConfirmResumeProcSaidAppend
Definition: ncftp.h:427
#define kCommandAvailabilityUnknown
Definition: ncftp.h:379
#define kDeleteYes
Definition: ncftp.h:368
#define kNetWriting
Definition: ncftp.h:302
int(* ConfirmResumeUploadProc)(const char *volatile localpath, volatile longest_int localsize, volatile time_t localmtime, const char *volatile *remotepath, volatile longest_int remotesize, volatile time_t remotetime, volatile longest_int *volatile startPoint)
Definition: ncftp.h:441
#define kLibraryMagic
Definition: ncftp.h:65
#define kPreferredMlsOpts
Definition: ncftp.h:399
#define kMlsOptPerm
Definition: ncftp.h:407
#define IsLocalPathDelim(c)
Definition: ncftp.h:497
#define kMlsOptUNIXmode
Definition: ncftp.h:404
#define kTypeBinary
Definition: ncftp.h:354
#define kMlsOptUNIXuid
Definition: ncftp.h:408
#define kRecursiveNo
Definition: ncftp.h:363
#define kMlsOptUNIXowner
Definition: ncftp.h:405
#define kCommandNotAvailable
Definition: ncftp.h:381
void(* FTPProgressMeterProc)(const FTPCIPtr, int)
Definition: ncftp.h:125
#define kAppendYes
Definition: ncftp.h:364
void StrRemoveTrailingSlashes(char *dst)
Definition: util.c:768
#define kRecursiveYes
Definition: ncftp.h:362
#define LIBNCFTP_USE_VAR(a)
Definition: ncftp.h:521
#define kErrLocalDeleteFailed
Definition: ncftp_errno.h:84
#define kErrSocketReadFailed
Definition: ncftp_errno.h:53
#define kNoErr
Definition: ncftp_errno.h:9
#define kErrWriteFailed
Definition: ncftp_errno.h:50
#define kErrMallocFailed
Definition: ncftp_errno.h:40
#define kErrLISTFailed
Definition: ncftp_errno.h:47
#define kErrOpenFailed
Definition: ncftp_errno.h:54
#define kErrLocalFileNewer
Definition: ncftp_errno.h:93
#define kErrSocketWriteFailed
Definition: ncftp_errno.h:52
#define kErrUTIMENotAvailable
Definition: ncftp_errno.h:82
#define kErrFdopenR
Definition: ncftp_errno.h:25
#define kErrRemoteFileNewer
Definition: ncftp_errno.h:94
#define kErrBadMagic
Definition: ncftp_errno.h:55
#define kErrNoValidFilesSpecified
Definition: ncftp_errno.h:91
#define kErrUserCanceled
Definition: ncftp_errno.h:112
#define kErrGeneric
Definition: ncftp_errno.h:13
#define kErrReadFailed
Definition: ncftp_errno.h:51
#define kErrRETRFailed
Definition: ncftp_errno.h:48
#define kErrBadParameter
Definition: ncftp_errno.h:56
#define kErrLocalSameAsRemote
Definition: ncftp_errno.h:95
#define kErrSetStartPoint
Definition: ncftp_errno.h:34
#define kErrRemoteHostClosedConnection
Definition: ncftp_errno.h:75
#define kErrDataTransferAborted
Definition: ncftp_errno.h:86
#define kErrNoBuf
Definition: ncftp_errno.h:92
#define kErrDataTimedOut
Definition: ncftp_errno.h:111
#define kErrLseekFailed
Definition: ncftp_errno.h:85
#define kErrSTORFailed
Definition: ncftp_errno.h:49
#define errno
Definition: errno.h:18
#define X_OK
Definition: io.h:169
_Check_return_ _CRTIMP int __cdecl dup2(_In_ int _FileHandleSrc, _In_ int _FileHandleDst)
_CRTIMP intptr_t __cdecl execv(_In_z_ const char *_Filename, _In_z_ char *const _ArgList[])
_Check_return_ _CRTIMP _CONST_RETURN char *__cdecl strrchr(_In_z_ const char *_Str, _In_ int _Ch)
#define exit(n)
Definition: config.h:202
int signal
Definition: except.c:82
static int fd
Definition: io.c:51
#define memset(x, y, z)
Definition: compat.h:39
#define StrDup
Definition: shlwapi.h:1533
INT WSAAPI shutdown(IN SOCKET s, IN INT how)
Definition: sockctrl.c:506
time_t nextProgressUpdate
Definition: ncftp.h:207
int dataTimedOut
Definition: ncftp.h:212
int hasRETRBUFSIZE
Definition: ncftp.h:171
char magic[16]
Definition: ncftp.h:135
double percentCompleted
Definition: ncftp.h:204
unsigned int xferTimeout
Definition: ncftp.h:141
double sec
Definition: ncftp.h:201
time_t mdtm
Definition: ncftp.h:206
size_t dataSocketRBufSize
Definition: ncftp.h:230
FTPProgressMeterProc progress
Definition: ncftp.h:198
double kBytesPerSec
Definition: ncftp.h:203
int numDownloads
Definition: ncftp.h:234
int hasSTORBUFSIZE
Definition: ncftp.h:174
longest_int startPoint
Definition: ncftp.h:159
const char * asciiFilenameExtensions
Definition: ncftp.h:246
int useProgressMeter
Definition: ncftp.h:199
double secLeft
Definition: ncftp.h:202
const char * rname
Definition: ncftp.h:208
size_t dataSocketSBufSize
Definition: ncftp.h:231
const char * lname
Definition: ncftp.h:209
struct timeval t0
Definition: ncftp.h:210
size_t bufSize
Definition: ncftp.h:187
longest_int expectedSize
Definition: ncftp.h:205
longest_int bytesTransferred
Definition: ncftp.h:197
char * buf
Definition: ncftp.h:186
FileInfoPtr first
Definition: ncftp.h:265
int nFileInfos
Definition: ncftp.h:269
longest_int size
Definition: ncftp.h:260
int type
Definition: ncftp.h:258
char * lname
Definition: ncftp.h:256
char * rlinkto
Definition: ncftp.h:255
time_t mdtm
Definition: ncftp.h:259
FileInfoPtr next
Definition: ncftp.h:252
char * rname
Definition: ncftp.h:254
Definition: ncftp.h:84
LinePtr first
Definition: ncftp.h:85
Definition: ncftp.h:79
char * line
Definition: ncftp.h:81
LinePtr next
Definition: ncftp.h:80
Definition: ftp_var.h:139
Definition: winsock.h:66
Definition: fci.c:127
Definition: parser.c:49
Definition: ps.c:97
unsigned long tv_sec
Definition: linux.h:1738
unsigned long tv_usec
Definition: linux.h:1739
time_t modtime
Definition: syshdrs.h:132
time_t actime
Definition: syshdrs.h:132
_In_ ULONG_PTR _In_ ULONG _Out_ ULONG_PTR * pid
Definition: winddi.h:3837
#define FD_ZERO(set)
Definition: winsock.h:96
#define FD_SET(fd, set)
Definition: winsock.h:89
#define getpid
Definition: wintirpc.h:52