ReactOS  0.4.14-dev-604-gcfdd483
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 
10 static 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
27 static sigjmp_buf gBrokenDataJmp;
28 #else
29 static jmp_buf gBrokenDataJmp;
30 #endif /* HAVE_SIGSETJMP */
31 static 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 
45 static int WaitForRemoteInput(const FTPCIPtr cip);
46 static int WaitForRemoteOutput(const FTPCIPtr cip);
47 
48 
49 #ifndef NO_SIGNALS
50 
51 static void
52 BrokenData(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 
70 void
72 {
73  cip->bytesTransferred = (longest_int) 0;
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 
92 void
94 {
95  (void) gettimeofday(&cip->t0, NULL);
96  if (cip->progress != (FTPProgressMeterProc) 0)
97  (*cip->progress)(cip, kPrInitMsg);
98 } /* FTPStartIOTimer */
99 
100 
101 
102 
103 void
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 
158 void
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  */
173 int
174 FTPList(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 
288 static 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 
365 int
366 FTPListToMemory2(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,
429  kNetReading,
430  kTypeAscii,
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 
564 static void
565 AutomaticallyUseASCIIModeDependingOnExtension(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  */
584 static 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 
649 static 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;
688  int zaction = kConfirmResumeProcSaidBestGuess;
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) {
698  fd = Open(file, O_RDONLY|O_BINARY, 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  */
721  if (cip->hasREST == kCommandAvailabilityUnknown) {
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) {
732  AutomaticallyUseASCIIModeDependingOnExtension(cip, dstfile, &xtype);
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. */
793  zaction = kConfirmResumeProcSaidSkip;
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  */
854  if (cip->hasSTORBUFSIZE == kCommandAvailable)
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,
934  kNetWriting,
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) {
1039  FTPAbortDataTransfer(cip);
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) {
1121  FTPAbortDataTransfer(cip);
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  }
1170 brk:
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 
1261 int
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 
1297 int
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) {
1340  return (kErrNoValidFilesSpecified);
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  */
1423 static 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 
1491 static int
1492 OpenTar(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 
1548 static int
1549 FTPGetOneTarF(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 
1644  (void) signal(SIGPIPE, SIG_IGN);
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
1675  (void) signal(SIGPIPE, SIG_IGN);
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) {
1715  FTPAbortDataTransfer(cip);
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");
1735  cip->errNo = kErrSocketReadFailed;
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");
1747  cip->errNo = kErrSocketReadFailed;
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 
1816 static 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)) {
1891  if (cip->hasREST == kCommandAvailabilityUnknown) {
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) {
1903  zaction = kConfirmResumeProcSaidAppend;
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;
1936  zaction = kConfirmResumeProcSaidResume;
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  */
1998  cip->errNo = kErrLocalFileNewer;
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 */
2037  cip->errNo = result = kErrSetStartPoint;
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  */
2093  if (cip->hasRETRBUFSIZE == kCommandAvailable)
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) {
2192  FTPAbortDataTransfer(cip);
2194  break;
2195  }
2196 #ifdef TESTING_ABOR
2197  if (cip->bytesTransferred > 0) {
2198  cip->cancelXfer = 1;
2199  FTPAbortDataTransfer(cip);
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");
2220  cip->errNo = kErrSocketReadFailed;
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) {
2318  FTPAbortDataTransfer(cip);
2320  break;
2321  }
2322 #ifdef TESTING_ABOR
2323  if (cip->bytesTransferred > 0) {
2324  cip->cancelXfer = 1;
2325  FTPAbortDataTransfer(cip);
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");
2346  cip->errNo = kErrSocketReadFailed;
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
2404 brk:
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 
2450 int
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 
2485 int
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 
2698 return_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 
2711 int
2712 FTPGetOneFile(const FTPCIPtr cip, const char *const file, const char *const dstfile)
2713 {
2714  return (FTPGetOneFile3(cip, file, dstfile, kTypeBinary, -1, kResumeNo, kAppendNo, kDeleteNo, (ConfirmResumeDownloadProc) 0, 0));
2715 } /* FTPGetOneFile */
2716 
2717 
2718 
2719 
2720 int
2721 FTPGetOneFile2(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 
2729 int
2730 FTPGetFiles(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 
2738 int
2739 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)
2740 {
2741  return (FTPGetFiles3(cip, pattern, dstdir, recurse, doGlob, xtype, resumeflag, appendflag, kDeleteNo, kTarYes, (ConfirmResumeDownloadProc) 0, 0));
2742 } /* FTPGetFiles2 */
2743 
2744 
2745 
2746 
2747 int
2748 FTPGetOneFileAscii(const FTPCIPtr cip, const char *const file, const char *const dstfile)
2749 {
2750  return (FTPGetOneFile3(cip, file, dstfile, kTypeAscii, -1, kResumeNo, kAppendNo, kDeleteNo, (ConfirmResumeDownloadProc) 0, 0));
2751 } /* FTPGetOneFileAscii */
2752 
2753 
2754 
2755 
2756 int
2757 FTPGetFilesAscii(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 
2765 int
2766 FTPPutOneFile(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 
2774 int
2775 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)
2776 {
2777  return (FTPPutOneFile3(cip, file, dstfile, xtype, fdtouse, appendflag, tmppfx, tmpsfx, kResumeNo, kDeleteNo, NoConfirmResumeUploadProc, 0));
2778 } /* FTPPutOneFile2 */
2779 
2780 
2781 
2782 
2783 int
2784 FTPPutFiles(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 
2792 int
2793 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)
2794 {
2795  return (FTPPutFiles3(cip, pattern, dstdir, recurse, doGlob, xtype, appendflag, tmppfx, tmpsfx, kResumeNo, kDeleteNo, NoConfirmResumeUploadProc, 0));
2796 } /* FTPPutFiles2 */
2797 
2798 
2799 
2800 
2801 int
2802 FTPPutOneFileAscii(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 
2810 int
2811 FTPPutFilesAscii(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 
2818 int
2819 FTPListToMemory(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 */
int ComputeRNames(FileInfoListPtr dst, const char *dstdir, int pflag, int nochop)
Definition: linelist.c:579
longest_int expectedSize
Definition: ncftp.h:205
void DisposeSReadlineInfo(SReadlineInfo *)
Definition: SReadline.c:57
Definition: winsock.h:66
#define EPIPE
Definition: acclib.h:91
int dataTimedOut
Definition: ncftp.h:212
#define SELECT_TYPE_ARG234
Definition: wincfg.h:4
#define kErrLISTFailed
Definition: ncftp_errno.h:47
#define IsLocalPathDelim(c)
Definition: ncftp.h:497
_In_ ULONG_PTR _In_ ULONG _Out_ ULONG_PTR * pid
Definition: winddi.h:3835
void FTPAbortDataTransfer(const FTPCIPtr cip)
Definition: rcmd.c:870
jmp_buf sigjmp_buf
Definition: port.h:324
#define kErrWriteFailed
Definition: ncftp_errno.h:50
#define kGlobNo
Definition: ncftp.h:361
static int WaitForRemoteInput(const FTPCIPtr cip)
Definition: io.c:1424
int FTPGetOneFile(const FTPCIPtr cip, const char *const file, const char *const dstfile)
Definition: io.c:2712
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
#define kErrBadParameter
Definition: ncftp_errno.h:56
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
Definition: typeof.h:49
const char * asciiFilenameExtensions
Definition: ncftp.h:246
#define kCommandAvailable
Definition: ncftp.h:380
int hasSTORBUFSIZE
Definition: ncftp.h:174
#define kTarYes
Definition: ncftp.h:370
struct timeval t0
Definition: ncftp.h:210
#define kConfirmResumeProcSaidSkip
Definition: ncftp.h:424
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 FTPLocalRecursiveFileList(FTPCIPtr cip, LineListPtr fileList, FileInfoListPtr files)
Definition: glob.c:1333
int SetStartOffset(const FTPCIPtr cip, longest_int restartPt)
Definition: ftp.c:853
static int gGotBrokenData
Definition: io.c:10
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
#define kErrOpenFailed
Definition: ncftp_errno.h:54
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
Definition: ftp_var.h:139
int FTPDelete(const FTPCIPtr cip, const char *const pattern, const int recurse, const int doGlob)
Definition: cmds.c:195
int InitSReadlineInfo(SReadlineInfo *, int, char *, size_t, int, int)
Definition: SReadline.c:24
#define kMlsOptModify
Definition: ncftp.h:403
#define kErrDataTransferAborted
Definition: ncftp_errno.h:86
int FTPGetFilesAscii(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob)
Definition: io.c:2757
#define free
Definition: debug_ros.c:5
__kernel_off_t off_t
Definition: linux.h:201
#define EINTR
Definition: acclib.h:80
unsigned long tv_sec
Definition: linux.h:1738
char * buf
Definition: ncftp.h:186
#define kPrInitMsg
Definition: ncftp.h:290
int FTPEndDataCmd(const FTPCIPtr, int)
Definition: rcmd.c:933
#define kCommandAvailabilityUnknown
Definition: ncftp.h:379
static int inbuf
Definition: adnsresfilter.c:73
double sec
Definition: ncftp.h:201
#define kErrSetStartPoint
Definition: ncftp_errno.h:34
int FTPFileModificationTime(const FTPCIPtr cip, const char *const file, time_t *const mdtm)
Definition: cmds.c:649
#define unlink
Definition: syshdrs.h:54
LinePtr next
Definition: ncftp.h:80
int BufferGets(char *, size_t, int, char *, char **, char **, size_t)
Definition: rcmd.c:978
#define STRNCPY(dst, src, n)
Definition: rdesktop.h:168
int FTPSetTransferType(const FTPCIPtr cip, int type)
Definition: cmds.c:836
static int fd
Definition: io.c:51
char * cmd
Definition: vfdcmd.c:85
#define kErrRETRFailed
Definition: ncftp_errno.h:48
#define kNoFirstSelect
Definition: sio.h:52
#define kErrMallocFailed
Definition: ncftp_errno.h:40
int errno
FTPProgressMeterProc progress
Definition: ncftp.h:198
_Check_return_ _CRTIMP _CONST_RETURN char *__cdecl strrchr(_In_z_ const char *_Str, _In_ int _Ch)
__u16 time
Definition: mkdosfs.c:366
int FTPMkdir(const FTPCIPtr cip, const char *const newDir, const int recurse)
Definition: cmds.c:641
char * lname
Definition: ncftp.h:256
#define FD_ZERO(set)
Definition: winsock.h:96
#define argv
Definition: mplay32.c:18
char * rname
Definition: ncftp.h:254
#define FD_SET(fd, set)
Definition: winsock.h:89
#define LIBNCFTP_USE_VAR(a)
Definition: ncftp.h:521
int FTPList(const FTPCIPtr cip, const int outfd, const int longMode, const char *const lsflag)
Definition: io.c:174
int LineListToFileInfoList(LineListPtr src, FileInfoListPtr dst)
Definition: linelist.c:758
char magic[16]
Definition: ncftp.h:135
#define kMlsOptUNIXuid
Definition: ncftp.h:408
#define kErrSocketReadFailed
Definition: ncftp_errno.h:53
int useProgressMeter
Definition: ncftp.h:199
#define kErrLseekFailed
Definition: ncftp_errno.h:85
#define kConfirmResumeProcSaidOverwrite
Definition: ncftp.h:426
void FTPUpdateIOTimer(const FTPCIPtr cip)
Definition: io.c:104
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(* 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 kConfirmResumeProcSaidResume
Definition: ncftp.h:425
__CRT_INLINE int __cdecl utime(const char *_Filename, struct utimbuf *_Utimbuf)
Definition: utime.h:136
int FTPCmd(const FTPCIPtr cip, const char *const cmdspec,...)
Definition: rcmd.c:603
#define Open
Definition: syshdrs.h:62
size_t dataSocketSBufSize
Definition: ncftp.h:231
int FTPPutFilesAscii(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob)
Definition: io.c:2811
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
#define write
Definition: acwin.h:97
#define gettimeofday(tv, tz)
Definition: adns_win32.h:159
#define kConfirmResumeProcSaidCancel
Definition: ncftp.h:429
#define StrDup
Definition: shlwapi.h:1533
#define kNetWriting
Definition: ncftp.h:302
GLuint GLsizei bufSize
Definition: glext.h:6040
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
#define chdir
Definition: syshdrs.h:69
double percentCompleted
Definition: ncftp.h:204
static void FTPRequestMlsOptions(const FTPCIPtr cip)
Definition: io.c:289
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
FileInfoPtr first
Definition: ncftp.h:265
_CRTIMP void __cdecl perror(_In_opt_z_ const char *_ErrMsg)
#define StrRemoveTrailingLocalPathDelim
Definition: ncftp.h:496
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
#define O_WRONLY
Definition: acwin.h:111
time_t now
Definition: finger.c:65
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 FTPPutOneFile(const FTPCIPtr cip, const char *const file, const char *const dstfile)
Definition: io.c:2766
int hasRETRBUFSIZE
Definition: ncftp.h:171
#define kMlsOptType
Definition: ncftp.h:401
r reserved
Definition: btrfs.c:2865
static const char mbstate_t *static wchar_t const char mbstate_t *static const wchar_t int *static double
Definition: string.c:80
int FTPLocalGlob(FTPCIPtr cip, LineListPtr fileList, const char *pattern, int doGlob)
Definition: glob.c:1580
int FTPGetOneFileAscii(const FTPCIPtr cip, const char *const file, const char *const dstfile)
Definition: io.c:2748
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
smooth NULL
Definition: ftsmooth.c:416
unsigned long tv_usec
Definition: linux.h:1739
#define kTimeoutErr
Definition: sio.h:58
int SWrite(int, const char *const, size_t, int, int)
Definition: SWrite.c:90
int FTPStartDataCmd(const FTPCIPtr, int, int, longest_int, const char *,...)
Definition: rcmd.c:763
#define kErrRemoteFileNewer
Definition: ncftp_errno.h:94
#define kRecursiveYes
Definition: ncftp.h:362
Definition: parser.c:48
void FTPInitIOTimer(const FTPCIPtr cip)
Definition: io.c:71
char * rlinkto
Definition: ncftp.h:255
#define UNUSED(x)
Definition: btrfs_drv.h:86
int SReadline(SReadlineInfo *, char *const, size_t)
Definition: SReadline.c:76
#define kPrEndMsg
Definition: ncftp.h:292
int longjmp(jmp_buf buf, int retval)
#define X_OK
Definition: io.h:169
time_t actime
Definition: syshdrs.h:132
_Check_return_ _CRTIMP int __cdecl dup2(_In_ int _FileHandleSrc, _In_ int _FileHandleDst)
const char * rname
Definition: ncftp.h:208
#define kRecursiveNo
Definition: ncftp.h:363
r l[0]
Definition: byte_order.h:167
int FTPPutFiles(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob)
Definition: io.c:2784
#define kDeleteNo
Definition: ncftp.h:369
#define STRNCAT(d, s)
Definition: Strn.h:48
__kernel_size_t size_t
Definition: linux.h:237
#define SEEK_SET
Definition: jmemansi.c:26
#define kResumeYes
Definition: ncftp.h:366
void siglongjmp(sigjmp_buf buf, int val)
GLfloat f
Definition: glext.h:7540
_CRTIMP int __cdecl getpid(void)
#define kErrSTORFailed
Definition: ncftp_errno.h:49
int nFileInfos
Definition: ncftp.h:269
void(* FTPProgressMeterProc)(const FTPCIPtr, int)
Definition: ncftp.h:125
int FTPRemoteRecursiveFileList1(FTPCIPtr cip, char *const rdir, FileInfoListPtr files)
Definition: glob.c:983
int ComputeLNames(FileInfoListPtr dst, const char *srcdir, const char *dstdir, int nochop)
Definition: linelist.c:663
if(!(yy_init))
Definition: macro.lex.yy.c:714
#define mkdir
Definition: acwin.h:101
#define kTarNo
Definition: ncftp.h:371
#define NoConfirmResumeUploadProc
Definition: ncftp.h:452
INT WSAAPI shutdown(IN SOCKET s, IN INT how)
Definition: sockctrl.c:506
int MkDirs(const char *const, int mode1)
Definition: util.c:785
#define S_ISDIR(mode)
Definition: various.h:18
#define kErrGeneric
Definition: ncftp_errno.h:13
int FTPRename(const FTPCIPtr cip, const char *const oldname, const char *const newname)
Definition: cmds.c:703
#define longest_int
Definition: ncftp.h:68
#define kErrBadMagic
Definition: ncftp_errno.h:55
#define kConfirmResumeProcSaidBestGuess
Definition: ncftp.h:428
static void AutomaticallyUseASCIIModeDependingOnExtension(const FTPCIPtr cip, const char *const pathName, int *const xtype)
Definition: io.c:565
int sigsetjmp(sigjmp_buf buf, int savesigs)
static int WaitForRemoteOutput(const FTPCIPtr cip)
Definition: io.c:585
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
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
const char file[]
Definition: icontest.c:11
const GLubyte * c
Definition: glext.h:8905
#define kErrLocalDeleteFailed
Definition: ncftp_errno.h:84
LinePtr AddLine(LineListPtr list, const char *buf1)
Definition: linelist.c:94
#define kNetReading
Definition: ncftp.h:303
#define kTypeBinary
Definition: ncftp.h:354
#define kPreferredMlsOpts
Definition: ncftp.h:399
BOOL Error
Definition: chkdsk.c:66
longest_int bytesTransferred
Definition: ncftp.h:197
#define kErrSocketWriteFailed
Definition: ncftp_errno.h:52
int FTPListToMemory(const FTPCIPtr cip, const char *const pattern, const LineListPtr llines, const char *const lsflags)
Definition: io.c:2819
void(* FTPSigProc)(int)
Definition: ncftp.h:76
#define kErrFdopenR
Definition: ncftp_errno.h:25
const char * FTPStrError(int e)
Definition: errno.c:114
Definition: ncftp.h:79
double secLeft
Definition: ncftp.h:202
int FTPFileSizeAndModificationTime(const FTPCIPtr cip, const char *const file, longest_int *const size, const int type, time_t *const mdtm)
Definition: cmds.c:1433
#define kTypeAscii
Definition: ncftp.h:353
#define kDeleteYes
Definition: ncftp.h:368
#define SIGPIPE
Definition: signal.h:35
#define kErrReadFailed
Definition: ncftp_errno.h:51
int signal
Definition: xcptfil.c:12
Definition: ncftp.h:84
unsigned int xferTimeout
Definition: ncftp.h:141
int FTPPutOneFileAscii(const FTPCIPtr cip, const char *const file, const char *const dstfile)
Definition: io.c:2802
#define kDontPerror
Definition: util.h:45
#define kMlsOptUNIXgid
Definition: ncftp.h:409
int FTPUtime(const FTPCIPtr cip, const char *const file, time_t actime, time_t modtime, time_t crtime)
Definition: cmds.c:1649
#define kDoPerror
Definition: util.h:44
#define NoConfirmResumeDownloadProc
Definition: ncftp.h:451
time_t nextProgressUpdate
Definition: ncftp.h:207
#define Lseek(a, b, c)
Definition: syshdrs.h:96
time_t modtime
Definition: syshdrs.h:132
#define O_TRUNC
Definition: acwin.h:112
LinePtr first
Definition: ncftp.h:85
int LineToFileInfoList(LinePtr lp, FileInfoListPtr dst)
Definition: linelist.c:775
GLenum src
Definition: glext.h:6340
#define close
Definition: acwin.h:98
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
#define kResumeNo
Definition: ncftp.h:367
#define kFullBufferNotRequired
Definition: sio.h:49
double kBytesPerSec
Definition: ncftp.h:203
size_t dataSocketRBufSize
Definition: ncftp.h:230
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 kErrLocalFileNewer
Definition: ncftp_errno.h:93
#define kCommandNotAvailable
Definition: ncftp.h:381
void FTPStopIOTimer(const FTPCIPtr cip)
Definition: io.c:159
#define kMlsOptUNIXgroup
Definition: ncftp.h:406
#define kPrUpdateMsg
Definition: ncftp.h:291
int type
Definition: ncftp.h:258
int FTPChdir(const FTPCIPtr cip, const char *const cdCwd)
Definition: cmds.c:11
time_t mdtm
Definition: ncftp.h:259
void FTPStartIOTimer(const FTPCIPtr cip)
Definition: io.c:93
int FTPRemoteGlob(FTPCIPtr cip, LineListPtr fileList, const char *pattern, int doGlob)
Definition: glob.c:1341
_Check_return_ _CRTIMP int __cdecl iscntrl(_In_ int _C)
void PrintF(const FTPCIPtr cip, const char *const fmt,...)
Definition: util.c:340
void DisposeFileInfoListContents(FileInfoListPtr list)
Definition: linelist.c:152
#define Stat
Definition: syshdrs.h:78
#define kErrUserCanceled
Definition: ncftp_errno.h:112
longest_int startPoint
Definition: ncftp.h:159
#define O_BINARY
Definition: io.c:41
#define kMlsOptPerm
Definition: ncftp.h:407
__kernel_time_t time_t
Definition: linux.h:252
GLuint GLint GLboolean GLint GLenum access
Definition: glext.h:7866
#define f
Definition: ke_i.h:83
GLenum GLenum dst
Definition: glext.h:6340
#define Fstat
Definition: syshdrs.h:79
void InitLineList(LineListPtr list)
Definition: linelist.c:54
int FTPGetCWD(const FTPCIPtr cip, char *const newCwd, const size_t newCwdSize)
Definition: cmds.c:254
int FTPIsDir(const FTPCIPtr cip, const char *const dir)
Definition: cmds.c:1531
const char * lname
Definition: ncftp.h:209
void StrRemoveTrailingSlashes(char *dst)
Definition: util.c:768
#define kConfirmResumeProcSaidAppend
Definition: ncftp.h:427
#define setjmp
Definition: setjmp.h:183
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
char * strchr(const char *String, int ch)
Definition: utclib.c:501
#define kErrNoBuf
Definition: ncftp_errno.h:92
#define kErrNoValidFilesSpecified
Definition: ncftp_errno.h:91
size_t bufSize
Definition: ncftp.h:187
#define kMlsOptUNIXowner
Definition: ncftp.h:405
#define kModTimeUnknown
Definition: ncftp.h:377
POINT cp
Definition: magnifier.c:59
#define kSizeUnknown
Definition: ncftp.h:376
#define kLibraryMagic
Definition: ncftp.h:65
#define kErrRemoteHostClosedConnection
Definition: ncftp_errno.h:75
#define c
Definition: ke_i.h:80
#define kMlsOptUNIXmode
Definition: ncftp.h:404
#define kNoErr
Definition: ncftp_errno.h:9
#define StrRFindLocalPathDelim(a)
Definition: ncftp.h:495
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
_CRTIMP intptr_t __cdecl execv(_In_z_ const char *_Filename, _In_z_ char *const _ArgList[])
#define kErrLocalSameAsRemote
Definition: ncftp_errno.h:95
#define kErrUTIMENotAvailable
Definition: ncftp_errno.h:82
#define kAppendYes
Definition: ncftp.h:364
void DisposeLineListContents(LineListPtr list)
Definition: linelist.c:33
long jmp_buf[100]
Definition: of.h:11
void exit(int exitcode)
Definition: _exit.c:33
#define ss
Definition: i386-dis.c:432
#define SIG_IGN
Definition: signal.h:48
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
GLuint64EXT * result
Definition: glext.h:11304
#define memset(x, y, z)
Definition: compat.h:39
static SERVICE_STATUS status
Definition: service.c:31
#define kErrDataTimedOut
Definition: ncftp_errno.h:111
#define S_ISREG(mode)
Definition: various.h:17
#define O_CREAT
Definition: acwin.h:110
char * line
Definition: ncftp.h:81
#define kAppendNo
Definition: ncftp.h:365
#define kMlsOptSize
Definition: ncftp.h:402
time_t mdtm
Definition: ncftp.h:206
longest_int size
Definition: ncftp.h:260
void FTPShutdownHost(const FTPCIPtr cip)
Definition: open.c:564
_CRTIMP int __cdecl read(_In_ int _FileHandle, _Out_writes_bytes_(_MaxCharCount) void *_DstBuf, _In_ unsigned int _MaxCharCount)
#define kMlsOptUnique
Definition: ncftp.h:410
int numDownloads
Definition: ncftp.h:234
int SRead(int, char *const, size_t, int, int)
Definition: SRead.c:118
int FilenameExtensionIndicatesASCII(const char *const pathName, const char *const extnList)
Definition: util.c:963
#define O_APPEND
Definition: fcntl.h:37
GLubyte * pattern
Definition: glext.h:7787
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
int FTPGetFiles(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob)
Definition: io.c:2730
#define O_RDONLY
Definition: acwin.h:108
Definition: fci.c:126
FileInfoPtr next
Definition: ncftp.h:252
Definition: ps.c:97
int FTPSymlink(const FTPCIPtr cip, const char *const lfrom, const char *const lto)
Definition: cmds.c:1585