ReactOS  0.4.14-dev-337-gf981a68
cmds.c
Go to the documentation of this file.
1 /* cmds.c
2  *
3  * Copyright (c) 1996-2001 Mike Gleason, NCEMRSoft.
4  * All rights reserved.
5  *
6  */
7 
8 #include "syshdrs.h"
9 
10 int
11 FTPChdir(const FTPCIPtr cip, const char *const cdCwd)
12 {
13  int result;
14 
15  if (cip == NULL)
16  return (kErrBadParameter);
17  if (strcmp(cip->magic, kLibraryMagic))
18  return (kErrBadMagic);
19 
20  if (cdCwd == NULL) {
23  } else {
24  if (cdCwd[0] == '\0') /* But allow FTPChdir(cip, ".") to go through. */
25  result = 2;
26  else if (strcmp(cdCwd, "..") == 0)
27  result = FTPCmd(cip, "CDUP");
28  else
29  result = FTPCmd(cip, "CWD %s", cdCwd);
30  if (result >= 0) {
31  if (result == 2) {
32  result = kNoErr;
33  } else {
35  cip->errNo = kErrCWDFailed;
36  }
37  }
38  }
39  return (result);
40 } /* FTPChdir */
41 
42 
43 
44 
45 int
46 FTPChmod(const FTPCIPtr cip, const char *const pattern, const char *const mode, const int doGlob)
47 {
48  LineList fileList;
49  LinePtr filePtr;
50  char *file;
51  int onceResult, batchResult;
52 
53  if (cip == NULL)
54  return (kErrBadParameter);
55  if (strcmp(cip->magic, kLibraryMagic))
56  return (kErrBadMagic);
57 
58  batchResult = FTPRemoteGlob(cip, &fileList, pattern, doGlob);
59  if (batchResult != kNoErr)
60  return (batchResult);
61 
62  for (batchResult = kNoErr, filePtr = fileList.first;
63  filePtr != NULL;
64  filePtr = filePtr->next)
65  {
66  file = filePtr->line;
67  if (file == NULL) {
68  batchResult = kErrBadLineList;
69  cip->errNo = kErrBadLineList;
70  break;
71  }
72  onceResult = FTPCmd(cip, "SITE CHMOD %s %s", mode, file);
73  if (onceResult < 0) {
74  batchResult = onceResult;
75  break;
76  }
77  if (onceResult != 2) {
78  batchResult = kErrChmodFailed;
79  cip->errNo = kErrChmodFailed;
80  }
81  }
82  DisposeLineListContents(&fileList);
83  return (batchResult);
84 } /* FTPChmod */
85 
86 
87 
88 
89 static int
91 {
92  LineList fileList;
93  LinePtr filePtr;
94  char *file;
95  int result;
96 
97  result = FTPRemoteGlob(cip, &fileList, "**", kGlobYes);
98  if (result != kNoErr) {
99  return (result);
100  }
101 
102  for (filePtr = fileList.first;
103  filePtr != NULL;
104  filePtr = filePtr->next)
105  {
106  file = filePtr->line;
107  if (file == NULL) {
108  cip->errNo = kErrBadLineList;
109  break;
110  }
111 
112  if ((file[0] == '.') && ((file[1] == '\0') || ((file[1] == '.') && (file[2] == '\0'))))
113  continue; /* Skip . and .. */
114 
115  if (FTPChdir(cip, file) == kNoErr) {
116  /* It was a directory.
117  * Go in and wax it.
118  */
120 
121  if (FTPChdir(cip, "..") != kNoErr) {
122  /* Panic -- we can no longer
123  * cd back to the directory
124  * we were in before.
125  */
128  return (result);
129  }
130 
131  if ((result < 0) && (result != kErrGlobNoMatch))
132  return (result);
133 
135  if (result != kNoErr) {
136  /* Well, we couldn't remove the empty
137  * directory. Perhaps we screwed up
138  * and the directory wasn't empty.
139  */
140  return (result);
141  }
142  } else {
143  /* Assume it was a file -- remove it. */
145  /* Try continuing to remove the rest,
146  * even if this failed.
147  */
148  }
149  }
150  DisposeLineListContents(&fileList);
151 
152  return (result);
153 } /* FTPRmdirRecursiveL2 */
154 
155 
156 
157 static int
158 FTPRmdirRecursive(const FTPCIPtr cip, const char *const dir)
159 {
160  int result, result2;
161 
162  /* Preserve old working directory. */
163  (void) FTPGetCWD(cip, cip->buf, cip->bufSize);
164 
165  result = FTPChdir(cip, dir);
166  if (result != kNoErr) {
167  return (result);
168  }
169 
171 
172  if (FTPChdir(cip, cip->buf) != kNoErr) {
173  /* Could not cd back to the original user directory -- bad. */
174  if (result != kNoErr) {
177  }
178  return (result);
179  }
180 
181  /* Now rmdir the last node, the root of the tree
182  * we just went through.
183  */
184  result2 = FTPRmdir(cip, dir, kRecursiveNo, kGlobNo);
185  if ((result2 != kNoErr) && (result == kNoErr))
186  result = result2;
187 
188  return (result);
189 } /* FTPRmdirRecursive */
190 
191 
192 
193 
194 int
195 FTPDelete(const FTPCIPtr cip, const char *const pattern, const int recurse, const int doGlob)
196 {
197  LineList fileList;
198  LinePtr filePtr;
199  char *file;
200  int onceResult, batchResult;
201 
202  if (cip == NULL)
203  return (kErrBadParameter);
204  if (strcmp(cip->magic, kLibraryMagic))
205  return (kErrBadMagic);
206 
207  batchResult = FTPRemoteGlob(cip, &fileList, pattern, doGlob);
208  if (batchResult != kNoErr)
209  return (batchResult);
210 
211  for (batchResult = kNoErr, filePtr = fileList.first;
212  filePtr != NULL;
213  filePtr = filePtr->next)
214  {
215  file = filePtr->line;
216  if (file == NULL) {
217  batchResult = kErrBadLineList;
218  cip->errNo = kErrBadLineList;
219  break;
220  }
221  onceResult = FTPCmd(cip, "DELE %s", file);
222  if (onceResult < 0) {
223  batchResult = onceResult;
224  break;
225  }
226  if (onceResult != 2) {
227  if (recurse != kRecursiveYes) {
228  batchResult = kErrDELEFailed;
229  cip->errNo = kErrDELEFailed;
230  } else {
231  onceResult = FTPCmd(cip, "RMD %s", file);
232  if (onceResult < 0) {
233  batchResult = onceResult;
234  break;
235  }
236  if (onceResult != 2) {
237  onceResult = FTPRmdirRecursive(cip, file);
238  if (onceResult < 0) {
239  batchResult = kErrRMDFailed;
240  cip->errNo = kErrRMDFailed;
241  }
242  }
243  }
244  }
245  }
246  DisposeLineListContents(&fileList);
247  return (batchResult);
248 } /* FTPDelete */
249 
250 
251 
252 
253 int
254 FTPGetCWD(const FTPCIPtr cip, char *const newCwd, const size_t newCwdSize)
255 {
256  ResponsePtr rp;
257  char *l, *r;
258  int result;
259 
260  if (cip == NULL)
261  return (kErrBadParameter);
262  if (strcmp(cip->magic, kLibraryMagic))
263  return (kErrBadMagic);
264 
265  if ((newCwd == NULL) || (newCwdSize == 0)) {
267  cip->errNo = kErrInvalidDirParam;
268  } else {
269  rp = InitResponse();
270  if (rp == NULL) {
272  cip->errNo = kErrMallocFailed;
273  Error(cip, kDontPerror, "Malloc failed.\n");
274  } else {
275  result = RCmd(cip, rp, "PWD");
276  if (result == 2) {
277  if ((r = strrchr(rp->msg.first->line, '"')) != NULL) {
278  /* "xxxx" is current directory.
279  * Strip out just the xxxx to copy into the remote cwd.
280  */
281  l = strchr(rp->msg.first->line, '"');
282  if ((l != NULL) && (l != r)) {
283  *r = '\0';
284  ++l;
285  (void) Strncpy(newCwd, l, newCwdSize);
286  *r = '"'; /* Restore, so response prints correctly. */
287  }
288  } else {
289  /* xxxx is current directory.
290  * Mostly for VMS.
291  */
292  if ((r = strchr(rp->msg.first->line, ' ')) != NULL) {
293  *r = '\0';
294  (void) Strncpy(newCwd, (rp->msg.first->line), newCwdSize);
295  *r = ' '; /* Restore, so response prints correctly. */
296  }
297  }
298  result = kNoErr;
299  } else if (result > 0) {
301  cip->errNo = kErrPWDFailed;
302  }
303  DoneWithResponse(cip, rp);
304  }
305  }
306  return (result);
307 } /* FTPGetCWD */
308 
309 
310 
311 
312 int
313 FTPChdirAndGetCWD(const FTPCIPtr cip, const char *const cdCwd, char *const newCwd, const size_t newCwdSize)
314 {
315  ResponsePtr rp;
316  char *l, *r;
317  int result;
318 
319  if (cip == NULL)
320  return (kErrBadParameter);
321  if (strcmp(cip->magic, kLibraryMagic))
322  return (kErrBadMagic);
323 
324  if ((newCwd == NULL) || (cdCwd == NULL)) {
326  cip->errNo = kErrInvalidDirParam;
327  } else {
328  if (cdCwd[0] == '\0') { /* But allow FTPChdir(cip, ".") to go through. */
329  result = FTPGetCWD(cip, newCwd, newCwdSize);
330  return (result);
331  }
332  rp = InitResponse();
333  if (rp == NULL) {
335  cip->errNo = kErrMallocFailed;
336  Error(cip, kDontPerror, "Malloc failed.\n");
337  } else {
338  if (strcmp(cdCwd, "..") == 0)
339  result = RCmd(cip, rp, "CDUP");
340  else
341  result = RCmd(cip, rp, "CWD %s", cdCwd);
342  if (result == 2) {
343  l = strchr(rp->msg.first->line, '"');
344  if ((l == rp->msg.first->line) && ((r = strrchr(rp->msg.first->line, '"')) != NULL) && (l != r)) {
345  /* "xxxx" is current directory.
346  * Strip out just the xxxx to copy into the remote cwd.
347  *
348  * This is nice because we didn't have to do a PWD.
349  */
350  *r = '\0';
351  ++l;
352  (void) Strncpy(newCwd, l, newCwdSize);
353  *r = '"'; /* Restore, so response prints correctly. */
354  DoneWithResponse(cip, rp);
355  result = kNoErr;
356  } else {
357  DoneWithResponse(cip, rp);
358  result = FTPGetCWD(cip, newCwd, newCwdSize);
359  }
360  } else if (result > 0) {
362  cip->errNo = kErrCWDFailed;
363  DoneWithResponse(cip, rp);
364  } else {
365  DoneWithResponse(cip, rp);
366  }
367  }
368  }
369  return (result);
370 } /* FTPChdirAndGetCWD */
371 
372 
373 
374 
375 int
376 FTPChdir3(FTPCIPtr cip, const char *const cdCwd, char *const newCwd, const size_t newCwdSize, int flags)
377 {
378  char *cp, *startcp;
379  int result;
380  int lastSubDir;
381  int mkd, pwd;
382 
383  if (cip == NULL)
384  return (kErrBadParameter);
385  if (strcmp(cip->magic, kLibraryMagic))
386  return (kErrBadMagic);
387 
388  if (cdCwd == NULL) {
390  cip->errNo = kErrInvalidDirParam;
391  return result;
392  }
393 
394  if (flags == kChdirOnly)
395  return (FTPChdir(cip, cdCwd));
396  if (flags == kChdirAndGetCWD) {
397  return (FTPChdirAndGetCWD(cip, cdCwd, newCwd, newCwdSize));
398  } else if (flags == kChdirAndMkdir) {
399  result = FTPMkdir(cip, cdCwd, kRecursiveYes);
400  if (result == kNoErr)
401  result = FTPChdir(cip, cdCwd);
402  return result;
403  } else if (flags == (kChdirAndMkdir|kChdirAndGetCWD)) {
404  result = FTPMkdir(cip, cdCwd, kRecursiveYes);
405  if (result == kNoErr)
406  result = FTPChdirAndGetCWD(cip, cdCwd, newCwd, newCwdSize);
407  return result;
408  }
409 
410  /* else: (flags | kChdirOneSubdirAtATime) == true */
411 
412  cp = cip->buf;
413  cp[cip->bufSize - 1] = '\0';
414  (void) Strncpy(cip->buf, cdCwd, cip->bufSize);
415  if (cp[cip->bufSize - 1] != '\0')
416  return (kErrBadParameter);
417 
418  mkd = (flags & kChdirAndMkdir);
419  pwd = (flags & kChdirAndGetCWD);
420 
421  if ((cdCwd[0] == '\0') || (strcmp(cdCwd, ".") == 0)) {
422  result = 0;
423  if (flags == kChdirAndGetCWD)
424  result = FTPGetCWD(cip, newCwd, newCwdSize);
425  return (result);
426  }
427 
428  lastSubDir = 0;
429  do {
430  startcp = cp;
432  if (cp != NULL) {
433  /* If this is the first slash in an absolute
434  * path, then startcp will be empty. We will
435  * use this below to treat this as the root
436  * directory.
437  */
438  *cp++ = '\0';
439  } else {
440  lastSubDir = 1;
441  }
442  if (strcmp(startcp, ".") == 0) {
443  result = 0;
444  if ((lastSubDir != 0) && (pwd != 0))
445  result = FTPGetCWD(cip, newCwd, newCwdSize);
446  } else if ((lastSubDir != 0) && (pwd != 0)) {
447  result = FTPChdirAndGetCWD(cip, (*startcp != '\0') ? startcp : "/", newCwd, newCwdSize);
448  } else {
449  result = FTPChdir(cip, (*startcp != '\0') ? startcp : "/");
450  }
451  if (result < 0) {
452  if ((mkd != 0) && (*startcp != '\0')) {
453  if (FTPCmd(cip, "MKD %s", startcp) == 2) {
454  result = FTPChdir(cip, startcp);
455  } else {
456  /* couldn't change nor create */
457  cip->errNo = result;
458  }
459  } else {
460  cip->errNo = result;
461  }
462  }
463  } while ((!lastSubDir) && (result == 0));
464 
465  return (result);
466 } /* FTPChdir3 */
467 
468 
469 
470 
471 int
472 FTPMkdir2(const FTPCIPtr cip, const char *const newDir, const int recurse, const char *const curDir)
473 {
474  int result, result2;
475  char *cp, *newTreeStart, *cp2;
476  char dir[512];
477  char dir2[512];
478  char c;
479 
480  if (cip == NULL)
481  return (kErrBadParameter);
482  if (strcmp(cip->magic, kLibraryMagic))
483  return (kErrBadMagic);
484 
485  if ((newDir == NULL) || (newDir[0] == '\0')) {
486  cip->errNo = kErrInvalidDirParam;
487  return (kErrInvalidDirParam);
488  }
489 
490  /* Preserve old working directory. */
491  if ((curDir == NULL) || (curDir[0] == '\0')) {
492  /* This hack is nice so you can eliminate an
493  * unnecessary "PWD" command on the server,
494  * since if you already knew what directory
495  * you're in. We want to minimize the number
496  * of client-server exchanges when feasible.
497  */
498  (void) FTPGetCWD(cip, cip->buf, cip->bufSize);
499  }
500 
501  result = FTPChdir(cip, newDir);
502  if (result == kNoErr) {
503  /* Directory already exists -- but we
504  * must now change back to where we were.
505  */
506  result2 = FTPChdir(cip, ((curDir == NULL) || (curDir[0] == '\0')) ? cip->buf : curDir);
507  if (result2 < 0) {
510  return (result);
511  }
512 
513  /* Don't need to create it. */
514  return (kNoErr);
515  }
516 
517  if (recurse == kRecursiveNo) {
518  result = FTPCmd(cip, "MKD %s", newDir);
519  if (result > 0) {
520  if (result != 2) {
521  Error(cip, kDontPerror, "MKD %s failed; [%s]\n", newDir, cip->lastFTPCmdResultStr);
523  cip->errNo = kErrMKDFailed;
524  return (result);
525  } else {
526  result = kNoErr;
527  }
528  }
529  } else {
530  (void) STRNCPY(dir, newDir);
531 
532  /* Strip trailing slashes. */
533  cp = dir + strlen(dir) - 1;
534  for (;;) {
535  if (cp <= dir) {
536  if ((newDir == NULL) || (newDir[0] == '\0')) {
537  cip->errNo = kErrInvalidDirParam;
539  return (result);
540  }
541  }
542  if ((*cp != '/') && (*cp != '\\')) {
543  cp[1] = '\0';
544  break;
545  }
546  --cp;
547  }
548  (void) STRNCPY(dir2, dir);
549 
550  if ((strrchr(dir, '/') == dir) || (strrchr(dir, '\\') == dir)) {
551  /* Special case "mkdir /subdir" */
552  result = FTPCmd(cip, "MKD %s", dir);
553  if (result < 0) {
554  return (result);
555  }
556  if (result != 2) {
557  Error(cip, kDontPerror, "MKD %s failed; [%s]\n", dir, cip->lastFTPCmdResultStr);
559  cip->errNo = kErrMKDFailed;
560  return (result);
561  }
562  /* Haven't chdir'ed, don't need to goto goback. */
563  return (kNoErr);
564  }
565 
566  for (;;) {
567  cp = strrchr(dir, '/');
568  if (cp == NULL)
569  cp = strrchr(dir, '\\');
570  if (cp == NULL) {
571  cp = dir + strlen(dir) - 1;
572  if (dir[0] == '\0') {
574  cip->errNo = kErrMKDFailed;
575  return (result);
576  }
577  /* Note: below we will refer to cp + 1
578  * which is why we set cp to point to
579  * the byte before the array begins!
580  */
581  cp = dir - 1;
582  break;
583  }
584  if (cp == dir) {
586  cip->errNo = kErrMKDFailed;
587  return (result);
588  }
589  *cp = '\0';
590  result = FTPChdir(cip, dir);
591  if (result == 0) {
592  break; /* Found a valid parent dir. */
593  /* from this point, we need to preserve old dir. */
594  }
595  }
596 
597  newTreeStart = dir2 + ((cp + 1) - dir);
598  for (cp = newTreeStart; ; ) {
599  cp2 = cp;
600  cp = strchr(cp2, '/');
601  c = '/';
602  if (cp == NULL)
603  cp = strchr(cp2, '\\');
604  if (cp != NULL) {
605  c = *cp;
606  *cp = '\0';
607  if (cp[1] == '\0') {
608  /* Done, if they did "mkdir /tmp/dir/" */
609  break;
610  }
611  }
612  result = FTPCmd(cip, "MKD %s", newTreeStart);
613  if (result < 0) {
614  return (result);
615  }
616  if (result != 2) {
617  Error(cip, kDontPerror, "Cwd=%s; MKD %s failed; [%s]\n", cip->buf, newTreeStart, cip->lastFTPCmdResultStr);
619  cip->errNo = kErrMKDFailed;
620  goto goback;
621  }
622  if (cp == NULL)
623  break; /* No more to make, done. */
624  *cp++ = c;
625  }
626  result = kNoErr;
627 
628 goback:
629  result2 = FTPChdir(cip, ((curDir == NULL) || (curDir[0] == '\0')) ? cip->buf : curDir);
630  if ((result == 0) && (result2 < 0)) {
633  }
634  }
635  return (result);
636 } /* FTPMkdir2 */
637 
638 
639 
640 int
641 FTPMkdir(const FTPCIPtr cip, const char *const newDir, const int recurse)
642 {
643  return (FTPMkdir2(cip, newDir, recurse, NULL));
644 } /* FTPMkdir */
645 
646 
647 
648 int
649 FTPFileModificationTime(const FTPCIPtr cip, const char *const file, time_t *const mdtm)
650 {
651  int result;
652  ResponsePtr rp;
653 
654  if (cip == NULL)
655  return (kErrBadParameter);
656  if (strcmp(cip->magic, kLibraryMagic))
657  return (kErrBadMagic);
658 
659  if ((mdtm == NULL) || (file == NULL))
660  return (kErrBadParameter);
661  *mdtm = kModTimeUnknown;
662 
663  if (cip->hasMDTM == kCommandNotAvailable) {
666  } else {
667  rp = InitResponse();
668  if (rp == NULL) {
670  cip->errNo = kErrMallocFailed;
671  Error(cip, kDontPerror, "Malloc failed.\n");
672  } else {
673  result = RCmd(cip, rp, "MDTM %s", file);
674  if (result < 0) {
675  DoneWithResponse(cip, rp);
676  return (result);
677  } else if (strncmp(rp->msg.first->line, "19100", 5) == 0) {
678  Error(cip, kDontPerror, "Warning: Server has Y2K Bug in \"MDTM\" command.\n");
679  cip->errNo = kErrMDTMFailed;
681  } else if (result == 2) {
682  *mdtm = UnMDTMDate(rp->msg.first->line);
683  cip->hasMDTM = kCommandAvailable;
684  result = kNoErr;
685  } else if (UNIMPLEMENTED_CMD(rp->code)) {
689  } else {
690  cip->errNo = kErrMDTMFailed;
692  }
693  DoneWithResponse(cip, rp);
694  }
695  }
696  return (result);
697 } /* FTPFileModificationTime */
698 
699 
700 
701 
702 int
703 FTPRename(const FTPCIPtr cip, const char *const oldname, const char *const newname)
704 {
705  int result;
706 
707  if (cip == NULL)
708  return (kErrBadParameter);
709  if (strcmp(cip->magic, kLibraryMagic))
710  return (kErrBadMagic);
711  if ((oldname == NULL) || (oldname[0] == '\0'))
712  return (kErrBadParameter);
713  if ((newname == NULL) || (oldname[0] == '\0'))
714  return (kErrBadParameter);
715 
716 
717  result = FTPCmd(cip, "RNFR %s", oldname);
718  if (result < 0)
719  return (result);
720  if (result != 3) {
721  cip->errNo = kErrRenameFailed;
722  return (cip->errNo);
723  }
724 
725  result = FTPCmd(cip, "RNTO %s", newname);
726  if (result < 0)
727  return (result);
728  if (result != 2) {
729  cip->errNo = kErrRenameFailed;
730  return (cip->errNo);
731  }
732  return (kNoErr);
733 } /* FTPRename */
734 
735 
736 
737 
738 int
739 FTPRemoteHelp(const FTPCIPtr cip, const char *const pattern, const LineListPtr llp)
740 {
741  int result;
742  ResponsePtr rp;
743 
744  if ((cip == NULL) || (llp == NULL))
745  return (kErrBadParameter);
746  if (strcmp(cip->magic, kLibraryMagic))
747  return (kErrBadMagic);
748 
749  InitLineList(llp);
750  rp = InitResponse();
751  if (rp == NULL) {
753  cip->errNo = kErrMallocFailed;
754  Error(cip, kDontPerror, "Malloc failed.\n");
755  } else {
756  if ((pattern == NULL) || (*pattern == '\0'))
757  result = RCmd(cip, rp, "HELP");
758  else
759  result = RCmd(cip, rp, "HELP %s", pattern);
760  if (result < 0) {
761  DoneWithResponse(cip, rp);
762  return (result);
763  } else if (result == 2) {
764  if (CopyLineList(llp, &rp->msg) < 0) {
766  cip->errNo = kErrMallocFailed;
767  Error(cip, kDontPerror, "Malloc failed.\n");
768  } else {
769  result = kNoErr;
770  }
771  } else {
772  cip->errNo = kErrHELPFailed;
774  }
775  DoneWithResponse(cip, rp);
776  }
777  return (result);
778 } /* FTPRemoteHelp */
779 
780 
781 
782 
783 int
784 FTPRmdir(const FTPCIPtr cip, const char *const pattern, const int recurse, const int doGlob)
785 {
786  LineList fileList;
787  LinePtr filePtr;
788  char *file;
789  int onceResult, batchResult;
790 
791  if (cip == NULL)
792  return (kErrBadParameter);
793  if (strcmp(cip->magic, kLibraryMagic))
794  return (kErrBadMagic);
795 
796  batchResult = FTPRemoteGlob(cip, &fileList, pattern, doGlob);
797  if (batchResult != kNoErr)
798  return (batchResult);
799 
800  for (batchResult = kNoErr, filePtr = fileList.first;
801  filePtr != NULL;
802  filePtr = filePtr->next)
803  {
804  file = filePtr->line;
805  if (file == NULL) {
806  batchResult = kErrBadLineList;
807  cip->errNo = kErrBadLineList;
808  break;
809  }
810  onceResult = FTPCmd(cip, "RMD %s", file);
811  if (onceResult < 0) {
812  batchResult = onceResult;
813  break;
814  }
815  if (onceResult != 2) {
816  if (recurse == kRecursiveYes) {
817  onceResult = FTPRmdirRecursive(cip, file);
818  if (onceResult < 0) {
819  batchResult = kErrRMDFailed;
820  cip->errNo = kErrRMDFailed;
821  }
822  } else {
823  batchResult = kErrRMDFailed;
824  cip->errNo = kErrRMDFailed;
825  }
826  }
827  }
828  DisposeLineListContents(&fileList);
829  return (batchResult);
830 } /* FTPRmdir */
831 
832 
833 
834 
835 int
837 {
838  int result;
839 
840  if (cip == NULL)
841  return (kErrBadParameter);
842  if (strcmp(cip->magic, kLibraryMagic))
843  return (kErrBadMagic);
844 
845  if (cip->curTransferType != type) {
846  switch (type) {
847  case kTypeAscii:
848  case kTypeBinary:
849  case kTypeEbcdic:
850  break;
851  case 'i':
852  case 'b':
853  case 'B':
854  type = kTypeBinary;
855  break;
856  case 'e':
857  type = kTypeEbcdic;
858  break;
859  case 'a':
860  type = kTypeAscii;
861  break;
862  default:
863  /* Yeah, we don't support Tenex. Who cares? */
864  Error(cip, kDontPerror, "Bad transfer type [%c].\n", type);
865  cip->errNo = kErrBadTransferType;
866  return (kErrBadTransferType);
867  }
868  result = FTPCmd(cip, "TYPE %c", type);
869  if (result != 2) {
871  cip->errNo = kErrTYPEFailed;
872  return (result);
873  }
874  cip->curTransferType = type;
875  }
876  return (kNoErr);
877 } /* FTPSetTransferType */
878 
879 
880 
881 
882 /* If the remote host supports the SIZE command, we can find out the exact
883  * size of a remote file, depending on the transfer type in use. SIZE
884  * returns different values for ascii and binary modes!
885  */
886 int
887 FTPFileSize(const FTPCIPtr cip, const char *const file, longest_int *const size, const int type)
888 {
889  int result;
890  ResponsePtr rp;
891 
892  if (cip == NULL)
893  return (kErrBadParameter);
894  if (strcmp(cip->magic, kLibraryMagic))
895  return (kErrBadMagic);
896 
897  if ((size == NULL) || (file == NULL))
898  return (kErrBadParameter);
899  *size = kSizeUnknown;
900 
902  if (result < 0)
903  return (result);
904 
905  if (cip->hasSIZE == kCommandNotAvailable) {
908  } else {
909  rp = InitResponse();
910  if (rp == NULL) {
912  cip->errNo = kErrMallocFailed;
913  Error(cip, kDontPerror, "Malloc failed.\n");
914  } else {
915  result = RCmd(cip, rp, "SIZE %s", file);
916  if (result < 0) {
917  DoneWithResponse(cip, rp);
918  return (result);
919  } else if (result == 2) {
920 #if defined(HAVE_LONG_LONG) && defined(SCANF_LONG_LONG)
922 #elif defined(HAVE_LONG_LONG) && defined(HAVE_STRTOQ)
923  *size = (longest_int) strtoq(rp->msg.first->line, NULL, 0);
924 #else
925  (void) sscanf(rp->msg.first->line, "%ld", size);
926 #endif
927  cip->hasSIZE = kCommandAvailable;
928  result = kNoErr;
929  } else if (UNIMPLEMENTED_CMD(rp->code)) {
933  } else {
934  cip->errNo = kErrSIZEFailed;
936  }
937  DoneWithResponse(cip, rp);
938  }
939  }
940  return (result);
941 } /* FTPFileSize */
942 
943 
944 
945 
946 int
947 FTPMListOneFile(const FTPCIPtr cip, const char *const file, const MLstItemPtr mlip)
948 {
949  int result;
950  ResponsePtr rp;
951 
952  /* We do a special check for older versions of NcFTPd which
953  * are based off of an incompatible previous version of IETF
954  * extensions.
955  *
956  * Roxen also seems to be way outdated, where MLST was on the
957  * data connection among other things.
958  *
959  */
960  if (
961  (cip->hasMLST == kCommandNotAvailable) ||
962  ((cip->serverType == kServerTypeNcFTPd) && (cip->ietfCompatLevel < 19981201)) ||
963  (cip->serverType == kServerTypeRoxen)
964  ) {
966  return (cip->errNo);
967  }
968 
969  rp = InitResponse();
970  if (rp == NULL) {
971  result = cip->errNo = kErrMallocFailed;
972  Error(cip, kDontPerror, "Malloc failed.\n");
973  } else {
974  result = RCmd(cip, rp, "MLST %s", file);
975  if (
976  (result == 2) &&
977  (rp->msg.first->line != NULL) &&
978  (rp->msg.first->next != NULL) &&
979  (rp->msg.first->next->line != NULL)
980  ) {
981  result = UnMlsT(rp->msg.first->next->line, mlip);
982  if (result < 0) {
984  }
985  } else if (UNIMPLEMENTED_CMD(rp->code)) {
989  } else {
990  cip->errNo = kErrMLSTFailed;
992  }
993  DoneWithResponse(cip, rp);
994  }
995 
996  return (result);
997 } /* FTPMListOneFile */
998 
999 
1000 
1001 
1002 /* We only use STAT to see if files or directories exist.
1003  * But since it is so rarely used in the wild, we need to
1004  * make sure the server supports the use where we pass
1005  * a pathname as a parameter.
1006  */
1007 int
1008 FTPFileExistsStat(const FTPCIPtr cip, const char *const file)
1009 {
1010  int result;
1011  ResponsePtr rp;
1012  LineList fileList;
1013  char savedCwd[512];
1014 
1015  if (cip == NULL)
1016  return (kErrBadParameter);
1017  if (strcmp(cip->magic, kLibraryMagic))
1018  return (kErrBadMagic);
1019 
1020  if (file == NULL)
1021  return (kErrBadParameter);
1022 
1025  return (result);
1026  }
1027 
1029  rp = InitResponse();
1030  if (rp == NULL) {
1032  cip->errNo = kErrMallocFailed;
1033  Error(cip, kDontPerror, "Malloc failed.\n");
1034  return (result);
1035 
1036  }
1037 
1038  /* First, make sure that when we STAT a pathname
1039  * that does not exist, that we get an error back.
1040  *
1041  * We also assume that a valid STAT response has
1042  * at least 3 lines of response text, typically
1043  * a "start" line, intermediate data, and then
1044  * a trailing line.
1045  *
1046  * We also can see a one-line case.
1047  */
1048  result = RCmd(cip, rp, "STAT %s", "NoSuchFile");
1049  if ((result == 2) && ((rp->msg.nLines >= 3) || (rp->msg.nLines == 1))) {
1050  /* Hmmm.... it gave back a positive
1051  * response. So STAT <file> does not
1052  * work correctly.
1053  */
1054  if (
1055  (rp->msg.first->next != NULL) &&
1056  (rp->msg.first->next->line != NULL) &&
1057  (
1058  (strstr(rp->msg.first->next->line, "o such file") != NULL) ||
1059  (strstr(rp->msg.first->next->line, "ot found") != NULL)
1060  )
1061  ) {
1062  /* OK, while we didn't want a 200
1063  * level response, some servers,
1064  * like wu-ftpd print an error
1065  * message "No such file or
1066  * directory" which we can special
1067  * case.
1068  */
1069  result = kNoErr;
1070  } else {
1073  DoneWithResponse(cip, rp);
1074  return (result);
1075  }
1076  }
1077  DoneWithResponse(cip, rp);
1078 
1079  /* We can't assume that we can simply say STAT rootdir/firstfile,
1080  * since the remote host may not be using / as a directory
1081  * delimiter. So we have to change to the root directory
1082  * and then do the STAT on that file.
1083  */
1084  if (
1085  (FTPGetCWD(cip, savedCwd, sizeof(savedCwd)) != kNoErr) ||
1086  (FTPChdir(cip, cip->startingWorkingDirectory) != kNoErr)
1087  ) {
1088  return (cip->errNo);
1089  }
1090 
1091  /* OK, we get an error when we stat
1092  * a non-existant file, but now we need to
1093  * see if we get a positive reply when
1094  * we stat a file that does exist.
1095  *
1096  * To do this, we list the root directory,
1097  * which we assume has one or more items.
1098  * If it doesn't, the user can't do anything
1099  * anyway. Then we stat the first item
1100  * we found to see if STAT says it exists.
1101  */
1102  if (
1103  ((result = FTPListToMemory2(cip, "", &fileList, "", 0, (int *) 0)) < 0) ||
1104  (fileList.last == NULL) ||
1105  (fileList.last->line == NULL)
1106  ) {
1107  /* Hmmm... well, in any case we can't use STAT. */
1110  DisposeLineListContents(&fileList);
1111  (void) FTPChdir(cip, savedCwd);
1112  return (result);
1113  }
1114 
1115  rp = InitResponse();
1116  if (rp == NULL) {
1118  cip->errNo = kErrMallocFailed;
1119  Error(cip, kDontPerror, "Malloc failed.\n");
1120  DisposeLineListContents(&fileList);
1121  (void) FTPChdir(cip, savedCwd);
1122  return (result);
1123 
1124  }
1125 
1126  result = RCmd(cip, rp, "STAT %s", fileList.last->line);
1127  DisposeLineListContents(&fileList);
1128 
1129  if ((result != 2) || (rp->msg.nLines == 2)) {
1130  /* Hmmm.... it gave back a negative
1131  * response. So STAT <file> does not
1132  * work correctly.
1133  */
1136  DoneWithResponse(cip, rp);
1137  (void) FTPChdir(cip, savedCwd);
1138  return (result);
1139  } else if (
1140  (rp->msg.first->next != NULL) &&
1141  (rp->msg.first->next->line != NULL) &&
1142  (
1143  (strstr(rp->msg.first->next->line, "o such file") != NULL) ||
1144  (strstr(rp->msg.first->next->line, "ot found") != NULL)
1145  )
1146  ) {
1147  /* Same special-case of the second line of STAT response. */
1150  DoneWithResponse(cip, rp);
1151  (void) FTPChdir(cip, savedCwd);
1152  return (result);
1153  }
1154  DoneWithResponse(cip, rp);
1156 
1157  /* Don't forget to change back to the original directory. */
1158  (void) FTPChdir(cip, savedCwd);
1159  }
1160 
1161  rp = InitResponse();
1162  if (rp == NULL) {
1164  cip->errNo = kErrMallocFailed;
1165  Error(cip, kDontPerror, "Malloc failed.\n");
1166  return (result);
1167  }
1168 
1169  result = RCmd(cip, rp, "STAT %s", file);
1170  if (result == 2) {
1171  result = kNoErr;
1172  if (((rp->msg.nLines >= 3) || (rp->msg.nLines == 1))) {
1173  if (
1174  (rp->msg.first->next != NULL) &&
1175  (rp->msg.first->next->line != NULL) &&
1176  (
1177  (strstr(rp->msg.first->next->line, "o such file") != NULL) ||
1178  (strstr(rp->msg.first->next->line, "ot found") != NULL)
1179  )
1180  ) {
1181  cip->errNo = kErrSTATFailed;
1183  } else {
1184  result = kNoErr;
1185  }
1186  } else if (rp->msg.nLines == 2) {
1187  cip->errNo = kErrSTATFailed;
1189  } else {
1190  result = kNoErr;
1191  }
1192  } else {
1193  cip->errNo = kErrSTATFailed;
1195  }
1196  DoneWithResponse(cip, rp);
1197  return (result);
1198 } /* FTPFileExistsStat */
1199 
1200 
1201 
1202 
1203 /* We only use STAT to see if files or directories exist.
1204  * But since it is so rarely used in the wild, we need to
1205  * make sure the server supports the use where we pass
1206  * a pathname as a parameter.
1207  */
1208 int
1209 FTPFileExistsNlst(const FTPCIPtr cip, const char *const file)
1210 {
1211  int result;
1212  LineList fileList, rootFileList;
1213  char savedCwd[512];
1214 
1215  if (cip == NULL)
1216  return (kErrBadParameter);
1217  if (strcmp(cip->magic, kLibraryMagic))
1218  return (kErrBadMagic);
1219 
1220  if (file == NULL)
1221  return (kErrBadParameter);
1222 
1225  return (result);
1226  }
1227 
1229  /* First, make sure that when we NLST a pathname
1230  * that does not exist, that we get an error back.
1231  *
1232  * We also assume that a valid NLST response has
1233  * at least 3 lines of response text, typically
1234  * a "start" line, intermediate data, and then
1235  * a trailing line.
1236  *
1237  * We also can see a one-line case.
1238  */
1239  if (
1240  ((FTPListToMemory2(cip, "NoSuchFile", &fileList, "", 0, (int *) 0)) == kNoErr) &&
1241  (fileList.nLines >= 1) &&
1242  (strstr(fileList.last->line, "o such file") == NULL) &&
1243  (strstr(fileList.last->line, "ot found") == NULL) &&
1244  (strstr(fileList.last->line, "o Such File") == NULL) &&
1245  (strstr(fileList.last->line, "ot Found") == NULL)
1246 
1247  ) {
1250  DisposeLineListContents(&fileList);
1251  return (result);
1252  }
1253  DisposeLineListContents(&fileList);
1254 
1255  /* We can't assume that we can simply say NLST rootdir/firstfile,
1256  * since the remote host may not be using / as a directory
1257  * delimiter. So we have to change to the root directory
1258  * and then do the NLST on that file.
1259  */
1260  if (
1261  (FTPGetCWD(cip, savedCwd, sizeof(savedCwd)) != kNoErr) ||
1262  (FTPChdir(cip, cip->startingWorkingDirectory) != kNoErr)
1263  ) {
1264  return (cip->errNo);
1265  }
1266 
1267  /* OK, we get an error when we list
1268  * a non-existant file, but now we need to
1269  * see if we get a positive reply when
1270  * we stat a file that does exist.
1271  *
1272  * To do this, we list the root directory,
1273  * which we assume has one or more items.
1274  * If it doesn't, the user can't do anything
1275  * anyway. Then we do the first item
1276  * we found to see if NLST says it exists.
1277  */
1278  if (
1279  ((result = FTPListToMemory2(cip, "", &rootFileList, "", 0, (int *) 0)) < 0) ||
1280  (rootFileList.last == NULL) ||
1281  (rootFileList.last->line == NULL)
1282  ) {
1283  /* Hmmm... well, in any case we can't use NLST. */
1286  DisposeLineListContents(&rootFileList);
1287  (void) FTPChdir(cip, savedCwd);
1288  return (result);
1289  }
1290 
1291  if (
1292  ((FTPListToMemory2(cip, rootFileList.last->line, &fileList, "", 0, (int *) 0)) == kNoErr) &&
1293  (fileList.nLines >= 1) &&
1294  (strstr(fileList.last->line, "o such file") == NULL) &&
1295  (strstr(fileList.last->line, "ot found") == NULL) &&
1296  (strstr(fileList.last->line, "o Such File") == NULL) &&
1297  (strstr(fileList.last->line, "ot Found") == NULL)
1298 
1299  ) {
1300  /* Good. We listed the item. */
1301  DisposeLineListContents(&fileList);
1302  DisposeLineListContents(&rootFileList);
1304 
1305  /* Don't forget to change back to the original directory. */
1306  (void) FTPChdir(cip, savedCwd);
1307  } else {
1310  DisposeLineListContents(&fileList);
1311  DisposeLineListContents(&rootFileList);
1312  (void) FTPChdir(cip, savedCwd);
1313  return (result);
1314  }
1315  }
1316 
1317  /* Check the requested item. */
1318  InitLineList(&fileList);
1319  if (
1320  ((FTPListToMemory2(cip, file, &fileList, "", 0, (int *) 0)) == kNoErr) &&
1321  (fileList.nLines >= 1) &&
1322  (strstr(fileList.last->line, "o such file") == NULL) &&
1323  (strstr(fileList.last->line, "ot found") == NULL) &&
1324  (strstr(fileList.last->line, "o Such File") == NULL) &&
1325  (strstr(fileList.last->line, "ot Found") == NULL)
1326 
1327  ) {
1328  /* The item existed. */
1329  result = kNoErr;
1330  } else {
1331  cip->errNo = kErrNLSTFailed;
1333  }
1334 
1335  DisposeLineListContents(&fileList);
1336  return (result);
1337 } /* FTPFileExistsNlst*/
1338 
1339 
1340 
1341 
1342 /* This functions goes to a great deal of trouble to try and determine if the
1343  * remote file specified exists. Newer servers support commands that make
1344  * it relatively inexpensive to find the answer, but older servers do not
1345  * provide a standard way. This means we may try a whole bunch of things,
1346  * but the good news is that the library saves information about which things
1347  * worked so if you do this again it uses the methods that work.
1348  */
1349 int
1350 FTPFileExists2(const FTPCIPtr cip, const char *const file, const int tryMDTM, const int trySIZE, const int tryMLST, const int trySTAT, const int tryNLST)
1351 {
1352  int result;
1353  time_t mdtm;
1354  longest_int size;
1355  MLstItem mlsInfo;
1356 
1357  if (tryMDTM != 0) {
1358  result = FTPFileModificationTime(cip, file, &mdtm);
1359  if (result == kNoErr)
1360  return (kNoErr);
1361  if (result == kErrMDTMFailed) {
1363  return (kErrNoSuchFileOrDirectory);
1364  }
1365  /* else keep going */
1366  }
1367 
1368  if (trySIZE != 0) {
1369  result = FTPFileSize(cip, file, &size, kTypeBinary);
1370  if (result == kNoErr)
1371  return (kNoErr);
1372  /* SIZE could fail if the server does
1373  * not support it for directories.
1374  *
1375  * if (result == kErrSIZEFailed)
1376  * return (kErrNoSuchFileOrDirectory);
1377  */
1378  /* else keep going */
1379  }
1380 
1381 
1382  if (tryMLST != 0) {
1383  result = FTPMListOneFile(cip, file, &mlsInfo);
1384  if (result == kNoErr)
1385  return (kNoErr);
1386  if (result == kErrMLSTFailed) {
1388  return (kErrNoSuchFileOrDirectory);
1389  }
1390  /* else keep going */
1391  }
1392 
1393  if (trySTAT != 0) {
1394  result = FTPFileExistsStat(cip, file);
1395  if (result == kNoErr)
1396  return (kNoErr);
1397  if (result == kErrSTATFailed) {
1399  return (kErrNoSuchFileOrDirectory);
1400  }
1401  /* else keep going */
1402  }
1403 
1404  if (tryNLST != 0) {
1405  result = FTPFileExistsNlst(cip, file);
1406  if (result == kNoErr)
1407  return (kNoErr);
1408  if (result == kErrNLSTFailed) {
1410  return (kErrNoSuchFileOrDirectory);
1411  }
1412  /* else keep going */
1413  }
1414 
1416  return (kErrCantTellIfFileExists);
1417 } /* FTPFileExists2 */
1418 
1419 
1420 
1421 
1422 int
1423 FTPFileExists(const FTPCIPtr cip, const char *const file)
1424 {
1425  return (FTPFileExists2(cip, file, 1, 1, 1, 1, 1));
1426 } /* FTPFileExists */
1427 
1428 
1429 
1430 
1431 
1432 int
1433 FTPFileSizeAndModificationTime(const FTPCIPtr cip, const char *const file, longest_int *const size, const int type, time_t *const mdtm)
1434 {
1435  MLstItem mlsInfo;
1436  int result;
1437 
1438  if (cip == NULL)
1439  return (kErrBadParameter);
1440  if (strcmp(cip->magic, kLibraryMagic))
1441  return (kErrBadMagic);
1442 
1443  if ((mdtm == NULL) || (size == NULL) || (file == NULL))
1444  return (kErrBadParameter);
1445 
1446  *mdtm = kModTimeUnknown;
1447  *size = kSizeUnknown;
1448 
1449  result = FTPSetTransferType(cip, type);
1450  if (result < 0)
1451  return (result);
1452 
1453  result = FTPMListOneFile(cip, file, &mlsInfo);
1454  if (result < 0) {
1455  /* Do it the regular way, where
1456  * we do a SIZE and then a MDTM.
1457  */
1458  result = FTPFileSize(cip, file, size, type);
1459  if (result < 0)
1460  return (result);
1461  result = FTPFileModificationTime(cip, file, mdtm);
1462  return (result);
1463  } else {
1464  *mdtm = mlsInfo.ftime;
1465  *size = mlsInfo.fsize;
1466  }
1467 
1468  return (result);
1469 } /* FTPFileSizeAndModificationTime */
1470 
1471 
1472 
1473 
1474 int
1475 FTPFileType(const FTPCIPtr cip, const char *const file, int *const ftype)
1476 {
1477  int result;
1478  MLstItem mlsInfo;
1479 
1480  if (cip == NULL)
1481  return (kErrBadParameter);
1482  if (strcmp(cip->magic, kLibraryMagic))
1483  return (kErrBadMagic);
1484 
1485  if ((file == NULL) || (file[0] == '\0')) {
1486  cip->errNo = kErrBadParameter;
1487  return (kErrBadParameter);
1488  }
1489 
1490  if (ftype == NULL) {
1491  cip->errNo = kErrBadParameter;
1492  return (kErrBadParameter);
1493  }
1494 
1495  *ftype = 0;
1496  result = FTPMListOneFile(cip, file, &mlsInfo);
1497  if (result == kNoErr) {
1498  *ftype = mlsInfo.ftype;
1499  return (kNoErr);
1500  }
1501 
1502  /* Preserve old working directory. */
1503  (void) FTPGetCWD(cip, cip->buf, cip->bufSize);
1504 
1505  result = FTPChdir(cip, file);
1506  if (result == kNoErr) {
1507  *ftype = 'd';
1508  /* Yes it was a directory, now go back to
1509  * where we were.
1510  */
1511  (void) FTPChdir(cip, cip->buf);
1512 
1513  /* Note: This improperly assumes that we
1514  * will be able to chdir back, which is
1515  * not guaranteed.
1516  */
1517  return (kNoErr);
1518  }
1519 
1520  result = FTPFileExists2(cip, file, 1, 1, 0, 1, 1);
1523 
1524  return (result);
1525 } /* FTPFileType */
1526 
1527 
1528 
1529 
1530 int
1531 FTPIsDir(const FTPCIPtr cip, const char *const dir)
1532 {
1533  int result, ftype;
1534 
1535  if (cip == NULL)
1536  return (kErrBadParameter);
1537  if (strcmp(cip->magic, kLibraryMagic))
1538  return (kErrBadMagic);
1539 
1540  if ((dir == NULL) || (dir[0] == '\0')) {
1541  cip->errNo = kErrInvalidDirParam;
1542  return (kErrInvalidDirParam);
1543  }
1544 
1545  result = FTPFileType(cip, dir, &ftype);
1547  result = 0;
1548  if (ftype == 'd')
1549  result = 1;
1550  }
1551  return (result);
1552 } /* FTPIsDir */
1553 
1554 
1555 
1556 
1557 int
1558 FTPIsRegularFile(const FTPCIPtr cip, const char *const file)
1559 {
1560  int result, ftype;
1561 
1562  if (cip == NULL)
1563  return (kErrBadParameter);
1564  if (strcmp(cip->magic, kLibraryMagic))
1565  return (kErrBadMagic);
1566 
1567  if ((file == NULL) || (file[0] == '\0')) {
1568  cip->errNo = kErrBadParameter;
1569  return (kErrBadParameter);
1570  }
1571 
1572  result = FTPFileType(cip, file, &ftype);
1574  result = 1;
1575  if (ftype == 'd')
1576  result = 0;
1577  }
1578  return (result);
1579 } /* FTPIsRegularFile */
1580 
1581 
1582 
1583 
1584 int
1585 FTPSymlink(const FTPCIPtr cip, const char *const lfrom, const char *const lto)
1586 {
1587  if (strcmp(cip->magic, kLibraryMagic))
1588  return (kErrBadMagic);
1589  if ((cip == NULL) || (lfrom == NULL) || (lto == NULL))
1590  return (kErrBadParameter);
1591  if ((lfrom[0] == '\0') || (lto[0] == '\0'))
1592  return (kErrBadParameter);
1593  if (FTPCmd(cip, "SITE SYMLINK %s %s", lfrom, lto) == 2)
1594  return (kNoErr);
1595  return (kErrSYMLINKFailed);
1596 } /* FTPSymlink */
1597 
1598 
1599 
1600 
1601 int
1602 FTPUmask(const FTPCIPtr cip, const char *const umsk)
1603 {
1604  if (cip == NULL)
1605  return (kErrBadParameter);
1606  if (strcmp(cip->magic, kLibraryMagic))
1607  return (kErrBadMagic);
1608  if ((umsk == NULL) || (umsk[0] == '\0'))
1609  return (kErrBadParameter);
1610  if (FTPCmd(cip, "SITE UMASK %s", umsk) == 2)
1611  return (kNoErr);
1612  return (kErrUmaskFailed);
1613 } /* FTPUmask */
1614 
1615 
1616 
1617 
1618 static void
1619 GmTimeStr(char *const dst, const size_t dstsize, time_t t)
1620 {
1621  char buf[64];
1622  struct tm *gtp;
1623 
1624  gtp = gmtime(&t);
1625  if (gtp == NULL) {
1626  dst[0] = '\0';
1627  } else {
1628 #ifdef HAVE_SNPRINTF
1629  buf[sizeof(buf) - 1] = '\0';
1630  (void) snprintf(buf, sizeof(buf) - 1, "%04d%02d%02d%02d%02d%02d",
1631 #else
1632  (void) sprintf(buf, "%04d%02d%02d%02d%02d%02d",
1633 #endif
1634  gtp->tm_year + 1900,
1635  gtp->tm_mon + 1,
1636  gtp->tm_mday,
1637  gtp->tm_hour,
1638  gtp->tm_min,
1639  gtp->tm_sec
1640  );
1641  (void) Strncpy(dst, buf, dstsize);
1642  }
1643 } /* GmTimeStr */
1644 
1645 
1646 
1647 
1648 int
1649 FTPUtime(const FTPCIPtr cip, const char *const file, time_t actime, time_t modtime, time_t crtime)
1650 {
1651  char mstr[64], astr[64], cstr[64];
1652  int result;
1653  ResponsePtr rp;
1654 
1655  if (cip == NULL)
1656  return (kErrBadParameter);
1657  if (strcmp(cip->magic, kLibraryMagic))
1658  return (kErrBadMagic);
1659 
1660  if (cip->hasUTIME == kCommandNotAvailable) {
1663  } else {
1664  if ((actime == (time_t) 0) || (actime == (time_t) -1))
1665  (void) time(&actime);
1666  if ((modtime == (time_t) 0) || (modtime == (time_t) -1))
1667  (void) time(&modtime);
1668  if ((crtime == (time_t) 0) || (crtime == (time_t) -1))
1669  crtime = modtime;
1670 
1671  (void) GmTimeStr(astr, sizeof(astr), actime);
1672  (void) GmTimeStr(mstr, sizeof(mstr), modtime);
1673  (void) GmTimeStr(cstr, sizeof(cstr), crtime);
1674 
1675  rp = InitResponse();
1676  if (rp == NULL) {
1678  cip->errNo = kErrMallocFailed;
1679  Error(cip, kDontPerror, "Malloc failed.\n");
1680  } else {
1681  result = RCmd(cip, rp, "SITE UTIME %s %s %s %s UTC", file, astr, mstr, cstr);
1682  if (result < 0) {
1683  DoneWithResponse(cip, rp);
1684  return (result);
1685  } else if (result == 2) {
1686  cip->hasUTIME = kCommandAvailable;
1687  result = kNoErr;
1688  } else if (UNIMPLEMENTED_CMD(rp->code)) {
1692  } else {
1693  cip->errNo = kErrUTIMEFailed;
1695  }
1696  DoneWithResponse(cip, rp);
1697  }
1698  }
1699  return (result);
1700 } /* FTPUtime */
#define kErrMDTMNotAvailable
Definition: ncftp_errno.h:66
LinePtr last
Definition: ncftp.h:85
int ietfCompatLevel
Definition: ncftp.h:233
#define kErrInvalidDirParam
Definition: ncftp_errno.h:39
#define kErrHELPFailed
Definition: ncftp_errno.h:83
int tm_min
Definition: time.h:78
#define kErrRMDFailed
Definition: ncftp_errno.h:43
#define kGlobNo
Definition: ncftp.h:361
int UnMlsT(const char *const line0, const MLstItemPtr mlip)
Definition: glob.c:693
static int FTPRmdirRecursiveL2(const FTPCIPtr cip)
Definition: cmds.c:90
#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
#define kCommandAvailable
Definition: ncftp.h:380
#define kErrNoSuchFileOrDirectory
Definition: ncftp_errno.h:105
int STATfileParamWorks
Definition: ncftp.h:179
int FTPRemoteHelp(const FTPCIPtr cip, const char *const pattern, const LineListPtr llp)
Definition: cmds.c:739
#define kErrUmaskFailed
Definition: ncftp_errno.h:60
int RCmd(const FTPCIPtr, ResponsePtr, const char *,...)
Definition: rcmd.c:718
#define kServerTypeNcFTPd
Definition: ncftp.h:463
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
int FTPDelete(const FTPCIPtr cip, const char *const pattern, const int recurse, const int doGlob)
Definition: cmds.c:195
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
char * strstr(char *String1, char *String2)
Definition: utclib.c:653
int FTPChmod(const FTPCIPtr cip, const char *const pattern, const char *const mode, const int doGlob)
Definition: cmds.c:46
char * buf
Definition: ncftp.h:186
int tm_mday
Definition: time.h:80
#define kCommandAvailabilityUnknown
Definition: ncftp.h:379
void DoneWithResponse(const FTPCIPtr, ResponsePtr)
Definition: rcmd.c:114
time_t UnMDTMDate(char *)
Definition: util.c:486
GLdouble GLdouble t
Definition: gl.h:2047
int FTPFileModificationTime(const FTPCIPtr cip, const char *const file, time_t *const mdtm)
Definition: cmds.c:649
LinePtr next
Definition: ncftp.h:80
#define snprintf
Definition: wintirpc.h:48
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
#define STRNCPY(dst, src, n)
Definition: rdesktop.h:168
#define kErrMKDFailed
Definition: ncftp_errno.h:57
longest_int fsize
Definition: ncftp.h:279
int FTPSetTransferType(const FTPCIPtr cip, int type)
Definition: cmds.c:836
#define kErrMallocFailed
Definition: ncftp_errno.h:40
int tm_year
Definition: time.h:82
_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
int NLSTfileParamWorks
Definition: ncftp.h:180
char magic[16]
Definition: ncftp.h:135
#define kErrNLSTFailed
Definition: ncftp_errno.h:103
int FTPFileExistsNlst(const FTPCIPtr cip, const char *const file)
Definition: cmds.c:1209
#define kErrMLSTNotAvailable
Definition: ncftp_errno.h:99
#define kErrGlobNoMatch
Definition: ncftp_errno.h:89
int FTPCmd(const FTPCIPtr cip, const char *const cmdspec,...)
Definition: rcmd.c:603
#define sprintf(buf, format,...)
Definition: sprintf.c:55
#define kErrPWDFailed
Definition: ncftp_errno.h:41
static int FTPRmdirRecursive(const FTPCIPtr cip, const char *const dir)
Definition: cmds.c:158
void modtime(int argc, const char *argv[])
Definition: cmds.c:2232
int FTPFileExistsStat(const FTPCIPtr cip, const char *const file)
Definition: cmds.c:1008
void pwd(int argc, const char *argv[])
Definition: cmds.c:1401
#define UNIMPLEMENTED_CMD(a)
Definition: ncftp.h:373
int FTPUmask(const FTPCIPtr cip, const char *const umsk)
Definition: cmds.c:1602
#define kErrNLSTwithFileNotAvailable
Definition: ncftp_errno.h:104
#define kErrCantTellIfFileExists
Definition: ncftp_errno.h:106
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
int FTPFileType(const FTPCIPtr cip, const char *const file, int *const ftype)
Definition: cmds.c:1475
#define kRecursiveYes
Definition: ncftp.h:362
_Check_return_ _CRTIMP int __cdecl sscanf(_In_z_ const char *_Src, _In_z_ _Scanf_format_string_ const char *_Format,...)
int tm_mon
Definition: time.h:81
unsigned int dir
Definition: maze.c:112
#define SCANF_LONG_LONG
Definition: wincfg.h:30
#define kServerTypeRoxen
Definition: ncftp.h:471
int FTPIsRegularFile(const FTPCIPtr cip, const char *const file)
Definition: cmds.c:1558
#define kRecursiveNo
Definition: ncftp.h:363
r l[0]
Definition: byte_order.h:167
char * startingWorkingDirectory
Definition: ncftp.h:158
int code
Definition: ncftp.h:92
#define kChdirOnly
Definition: ncftp.h:417
int nLines
Definition: ncftp.h:86
#define kErrMLSTFailed
Definition: ncftp_errno.h:97
GLsizeiptr size
Definition: glext.h:5919
#define kChdirAndGetCWD
Definition: ncftp.h:419
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
const char file[]
Definition: icontest.c:11
const GLubyte * c
Definition: glext.h:8905
#define kGlobYes
Definition: ncftp.h:360
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
#define kErrSIZEFailed
Definition: ncftp_errno.h:62
int CopyLineList(LineListPtr dst, LineListPtr src)
Definition: linelist.c:127
#define kErrSIZENotAvailable
Definition: ncftp_errno.h:65
#define kTypeBinary
Definition: ncftp.h:354
#define kErrMDTMFailed
Definition: ncftp_errno.h:63
BOOL Error
Definition: chkdsk.c:66
#define kErrSTATwithFileNotAvailable
Definition: ncftp_errno.h:102
Definition: ncftp.h:89
GLbitfield flags
Definition: glext.h:7161
time_t ftime
Definition: ncftp.h:280
#define kErrChmodFailed
Definition: ncftp_errno.h:59
Definition: ncftp.h:79
#define kErrInvalidMLSTResponse
Definition: ncftp_errno.h:98
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 kErrCannotGoToPrevDir
Definition: ncftp_errno.h:58
#define kErrTYPEFailed
Definition: ncftp_errno.h:64
#define kTypeEbcdic
Definition: ncftp.h:355
Definition: ncftp.h:84
char lastFTPCmdResultStr[128]
Definition: ncftp.h:214
#define kDontPerror
Definition: util.h:45
int FTPUtime(const FTPCIPtr cip, const char *const file, time_t actime, time_t modtime, time_t crtime)
Definition: cmds.c:1649
LinePtr first
Definition: ncftp.h:85
Definition: time.h:76
GLenum mode
Definition: glext.h:6217
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 kCommandNotAvailable
Definition: ncftp.h:381
int ftype
Definition: ncftp.h:278
int FTPChdir(const FTPCIPtr cip, const char *const cdCwd)
Definition: cmds.c:11
int FTPRmdir(const FTPCIPtr cip, const char *const pattern, const int recurse, const int doGlob)
Definition: cmds.c:784
int FTPChdir3(FTPCIPtr cip, const char *const cdCwd, char *const newCwd, const size_t newCwdSize, int flags)
Definition: cmds.c:376
int FTPRemoteGlob(FTPCIPtr cip, LineListPtr fileList, const char *pattern, int doGlob)
Definition: glob.c:1341
LineList msg
Definition: ncftp.h:90
int FTPChdirAndGetCWD(const FTPCIPtr cip, const char *const cdCwd, char *const newCwd, const size_t newCwdSize)
Definition: cmds.c:313
#define kChdirAndMkdir
Definition: ncftp.h:418
__kernel_time_t time_t
Definition: linux.h:252
char * Strncpy(char *const, const char *const, const size_t)
Definition: Strncpy.c:11
int curTransferType
Definition: ncftp.h:157
GLenum GLenum dst
Definition: glext.h:6340
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
#define kErrSYMLINKFailed
Definition: ncftp_errno.h:87
#define kErrFileExistsButCannotDetermineType
Definition: ncftp_errno.h:107
int FTPFileSize(const FTPCIPtr cip, const char *const file, longest_int *const size, const int type)
Definition: cmds.c:887
#define kErrSTATFailed
Definition: ncftp_errno.h:101
#define kErrUTIMEFailed
Definition: ncftp_errno.h:81
char * strchr(const char *String, int ch)
Definition: utclib.c:501
int tm_sec
Definition: time.h:77
size_t bufSize
Definition: ncftp.h:187
#define kModTimeUnknown
Definition: ncftp.h:377
POINT cp
Definition: magnifier.c:59
#define kSizeUnknown
Definition: ncftp.h:376
#define kErrBadLineList
Definition: ncftp_errno.h:44
#define kLibraryMagic
Definition: ncftp.h:65
#define c
Definition: ke_i.h:80
int tm_hour
Definition: time.h:79
#define kNoErr
Definition: ncftp_errno.h:9
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
_CRTIMP struct tm *__cdecl gmtime(const time_t *_Time)
Definition: time.h:423
#define kErrUTIMENotAvailable
Definition: ncftp_errno.h:82
#define kErrDELEFailed
Definition: ncftp_errno.h:61
void DisposeLineListContents(LineListPtr list)
Definition: linelist.c:33
int FTPFileExists(const FTPCIPtr cip, const char *const file)
Definition: cmds.c:1423
#define kErrBadTransferType
Definition: ncftp_errno.h:38
ResponsePtr InitResponse(void)
Definition: rcmd.c:38
GLuint64EXT * result
Definition: glext.h:11304
int FTPMListOneFile(const FTPCIPtr cip, const char *const file, const MLstItemPtr mlip)
Definition: cmds.c:947
char * line
Definition: ncftp.h:81
#define StrFindLocalPathDelim(a)
Definition: ncftp.h:494
#define kErrCWDFailed
Definition: ncftp_errno.h:42
int FTPMkdir2(const FTPCIPtr cip, const char *const newDir, const int recurse, const char *const curDir)
Definition: cmds.c:472
static void GmTimeStr(char *const dst, const size_t dstsize, time_t t)
Definition: cmds.c:1619
GLubyte * pattern
Definition: glext.h:7787
Definition: fci.c:126
#define kErrRenameFailed
Definition: ncftp_errno.h:67
int FTPSymlink(const FTPCIPtr cip, const char *const lfrom, const char *const lto)
Definition: cmds.c:1585