ReactOS 0.4.15-dev-7924-g5949c20
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
10int
11FTPChdir(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
45int
46FTPChmod(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;
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;
80 }
81 }
82 DisposeLineListContents(&fileList);
83 return (batchResult);
84} /* FTPChmod */
85
86
87
88
89static 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
157static int
158FTPRmdirRecursive(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
194int
195FTPDelete(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
253int
254FTPGetCWD(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)) {
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
312int
313FTPChdirAndGetCWD(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)) {
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
375int
376FTPChdir3(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) {
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);
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
471int
472FTPMkdir2(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')) {
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')) {
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
628goback:
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
640int
641FTPMkdir(const FTPCIPtr cip, const char *const newDir, const int recurse)
642{
643 return (FTPMkdir2(cip, newDir, recurse, NULL));
644} /* FTPMkdir */
645
646
647
648int
649FTPFileModificationTime(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);
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
702int
703FTPRename(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
738int
739FTPRemoteHelp(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
783int
784FTPRmdir(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
835int
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':
855 break;
856 case 'e':
858 break;
859 case 'a':
861 break;
862 default:
863 /* Yeah, we don't support Tenex. Who cares? */
864 Error(cip, kDontPerror, "Bad transfer type [%c].\n", type);
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 */
886int
887FTPFileSize(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);
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
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
946int
947FTPMListOneFile(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)) ||
964 ) {
966 return (cip->errNo);
967 }
968
969 rp = InitResponse();
970 if (rp == NULL) {
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 */
1007int
1008FTPFileExistsStat(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) ||
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 */
1208int
1209FTPFileExistsNlst(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) ||
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 */
1349int
1350FTPFileExists2(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;
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) {
1364 }
1365 /* else keep going */
1366 }
1367
1368 if (trySIZE != 0) {
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) {
1389 }
1390 /* else keep going */
1391 }
1392
1393 if (trySTAT != 0) {
1395 if (result == kNoErr)
1396 return (kNoErr);
1397 if (result == kErrSTATFailed) {
1400 }
1401 /* else keep going */
1402 }
1403
1404 if (tryNLST != 0) {
1406 if (result == kNoErr)
1407 return (kNoErr);
1408 if (result == kErrNLSTFailed) {
1411 }
1412 /* else keep going */
1413 }
1414
1416 return (kErrCantTellIfFileExists);
1417} /* FTPFileExists2 */
1418
1419
1420
1421
1422int
1423FTPFileExists(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
1432int
1433FTPFileSizeAndModificationTime(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
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
1474int
1475FTPFileType(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
1530int
1531FTPIsDir(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')) {
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
1557int
1558FTPIsRegularFile(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
1584int
1585FTPSymlink(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
1601int
1602FTPUmask(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
1618static void
1619GmTimeStr(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
1648int
1649FTPUtime(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) {
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 */
char * Strncpy(char *const, const char *const, const size_t)
Definition: Strncpy.c:11
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
char * strstr(char *String1, char *String2)
Definition: utclib.c:653
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
char * strchr(const char *String, int ch)
Definition: utclib.c:501
unsigned int dir
Definition: maze.c:112
#define STRNCPY(dst, src, n)
Definition: rdesktop.h:168
void pwd(int argc, const char *argv[])
Definition: cmds.c:1401
void modtime(int argc, const char *argv[])
Definition: cmds.c:2232
BOOL Error
Definition: chkdsk.c:66
r l[0]
Definition: byte_order.h:168
#define NULL
Definition: types.h:112
__kernel_time_t time_t
Definition: linux.h:252
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
GLdouble GLdouble t
Definition: gl.h:2047
GLsizeiptr size
Definition: glext.h:5919
const GLubyte * c
Definition: glext.h:8905
GLubyte * pattern
Definition: glext.h:7787
GLenum mode
Definition: glext.h:6217
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLenum GLenum dst
Definition: glext.h:6340
GLbitfield flags
Definition: glext.h:7161
GLuint64EXT * result
Definition: glext.h:11304
int UnMlsT(const char *const line0, const MLstItemPtr mlip)
Definition: glob.c:693
int FTPRemoteGlob(FTPCIPtr cip, LineListPtr fileList, const char *pattern, int doGlob)
Definition: glob.c:1341
_Check_return_ _CRTIMP int __cdecl sscanf(_In_z_ const char *_Src, _In_z_ _Scanf_format_string_ const char *_Format,...)
#define c
Definition: ke_i.h:80
#define SCANF_LONG_LONG
Definition: wincfg.h:30
void InitLineList(LineListPtr list)
Definition: linelist.c:54
void DisposeLineListContents(LineListPtr list)
Definition: linelist.c:33
int CopyLineList(LineListPtr dst, LineListPtr src)
Definition: linelist.c:127
POINT cp
Definition: magnifier.c:59
__u16 time
Definition: mkdosfs.c:8
int FTPMListOneFile(const FTPCIPtr cip, const char *const file, const MLstItemPtr mlip)
Definition: cmds.c:947
int FTPRmdir(const FTPCIPtr cip, const char *const pattern, const int recurse, const int doGlob)
Definition: cmds.c:784
int FTPSymlink(const FTPCIPtr cip, const char *const lfrom, const char *const lto)
Definition: cmds.c:1585
int FTPFileSizeAndModificationTime(const FTPCIPtr cip, const char *const file, longest_int *const size, const int type, time_t *const mdtm)
Definition: cmds.c:1433
static void GmTimeStr(char *const dst, const size_t dstsize, time_t t)
Definition: cmds.c:1619
int FTPFileExistsStat(const FTPCIPtr cip, const char *const file)
Definition: cmds.c:1008
int FTPMkdir(const FTPCIPtr cip, const char *const newDir, const int recurse)
Definition: cmds.c:641
int FTPFileType(const FTPCIPtr cip, const char *const file, int *const ftype)
Definition: cmds.c:1475
int FTPUtime(const FTPCIPtr cip, const char *const file, time_t actime, time_t modtime, time_t crtime)
Definition: cmds.c:1649
int FTPFileModificationTime(const FTPCIPtr cip, const char *const file, time_t *const mdtm)
Definition: cmds.c:649
int FTPMkdir2(const FTPCIPtr cip, const char *const newDir, const int recurse, const char *const curDir)
Definition: cmds.c:472
int FTPFileExistsNlst(const FTPCIPtr cip, const char *const file)
Definition: cmds.c:1209
static int FTPRmdirRecursive(const FTPCIPtr cip, const char *const dir)
Definition: cmds.c:158
int FTPFileExists2(const FTPCIPtr cip, const char *const file, const int tryMDTM, const int trySIZE, const int tryMLST, const int trySTAT, const int tryNLST)
Definition: cmds.c:1350
int FTPChmod(const FTPCIPtr cip, const char *const pattern, const char *const mode, const int doGlob)
Definition: cmds.c:46
int FTPUmask(const FTPCIPtr cip, const char *const umsk)
Definition: cmds.c:1602
int FTPDelete(const FTPCIPtr cip, const char *const pattern, const int recurse, const int doGlob)
Definition: cmds.c:195
int FTPRemoteHelp(const FTPCIPtr cip, const char *const pattern, const LineListPtr llp)
Definition: cmds.c:739
int FTPGetCWD(const FTPCIPtr cip, char *const newCwd, const size_t newCwdSize)
Definition: cmds.c:254
int FTPRename(const FTPCIPtr cip, const char *const oldname, const char *const newname)
Definition: cmds.c:703
int FTPIsDir(const FTPCIPtr cip, const char *const dir)
Definition: cmds.c:1531
int FTPChdir(const FTPCIPtr cip, const char *const cdCwd)
Definition: cmds.c:11
int FTPIsRegularFile(const FTPCIPtr cip, const char *const file)
Definition: cmds.c:1558
static int FTPRmdirRecursiveL2(const FTPCIPtr cip)
Definition: cmds.c:90
int FTPChdir3(FTPCIPtr cip, const char *const cdCwd, char *const newCwd, const size_t newCwdSize, int flags)
Definition: cmds.c:376
int FTPFileSize(const FTPCIPtr cip, const char *const file, longest_int *const size, const int type)
Definition: cmds.c:887
int FTPSetTransferType(const FTPCIPtr cip, int type)
Definition: cmds.c:836
int FTPFileExists(const FTPCIPtr cip, const char *const file)
Definition: cmds.c:1423
int FTPChdirAndGetCWD(const FTPCIPtr cip, const char *const cdCwd, char *const newCwd, const size_t newCwdSize)
Definition: cmds.c:313
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 kDontPerror
Definition: util.h:45
#define sprintf(buf, format,...)
Definition: sprintf.c:55
#define kGlobNo
Definition: ncftp.h:361
int FTPCmd(const FTPCIPtr cip, const char *const cmdspec,...)
Definition: rcmd.c:603
int RCmd(const FTPCIPtr, ResponsePtr, const char *,...)
Definition: rcmd.c:718
#define kTypeAscii
Definition: ncftp.h:353
#define kChdirAndGetCWD
Definition: ncftp.h:419
#define kSizeUnknown
Definition: ncftp.h:376
#define kServerTypeNcFTPd
Definition: ncftp.h:463
#define UNIMPLEMENTED_CMD(a)
Definition: ncftp.h:373
#define kCommandAvailable
Definition: ncftp.h:380
#define kModTimeUnknown
Definition: ncftp.h:377
#define longest_int
Definition: ncftp.h:68
void DoneWithResponse(const FTPCIPtr, ResponsePtr)
Definition: rcmd.c:114
#define StrFindLocalPathDelim(a)
Definition: ncftp.h:494
#define kGlobYes
Definition: ncftp.h:360
time_t UnMDTMDate(char *)
Definition: util.c:486
#define kCommandAvailabilityUnknown
Definition: ncftp.h:379
#define kLibraryMagic
Definition: ncftp.h:65
#define kTypeEbcdic
Definition: ncftp.h:355
#define kChdirAndMkdir
Definition: ncftp.h:418
#define kTypeBinary
Definition: ncftp.h:354
#define kRecursiveNo
Definition: ncftp.h:363
#define kCommandNotAvailable
Definition: ncftp.h:381
#define kRecursiveYes
Definition: ncftp.h:362
#define kChdirOnly
Definition: ncftp.h:417
ResponsePtr InitResponse(void)
Definition: rcmd.c:38
#define kServerTypeRoxen
Definition: ncftp.h:471
#define kErrMDTMFailed
Definition: ncftp_errno.h:63
#define kErrSTATwithFileNotAvailable
Definition: ncftp_errno.h:102
#define kErrUTIMEFailed
Definition: ncftp_errno.h:81
#define kErrSYMLINKFailed
Definition: ncftp_errno.h:87
#define kErrTYPEFailed
Definition: ncftp_errno.h:64
#define kErrNLSTwithFileNotAvailable
Definition: ncftp_errno.h:104
#define kErrDELEFailed
Definition: ncftp_errno.h:61
#define kNoErr
Definition: ncftp_errno.h:9
#define kErrMLSTNotAvailable
Definition: ncftp_errno.h:99
#define kErrGlobNoMatch
Definition: ncftp_errno.h:89
#define kErrInvalidDirParam
Definition: ncftp_errno.h:39
#define kErrMallocFailed
Definition: ncftp_errno.h:40
#define kErrCantTellIfFileExists
Definition: ncftp_errno.h:106
#define kErrMDTMNotAvailable
Definition: ncftp_errno.h:66
#define kErrBadTransferType
Definition: ncftp_errno.h:38
#define kErrChmodFailed
Definition: ncftp_errno.h:59
#define kErrUTIMENotAvailable
Definition: ncftp_errno.h:82
#define kErrMKDFailed
Definition: ncftp_errno.h:57
#define kErrRMDFailed
Definition: ncftp_errno.h:43
#define kErrPWDFailed
Definition: ncftp_errno.h:41
#define kErrBadMagic
Definition: ncftp_errno.h:55
#define kErrNoSuchFileOrDirectory
Definition: ncftp_errno.h:105
#define kErrInvalidMLSTResponse
Definition: ncftp_errno.h:98
#define kErrBadParameter
Definition: ncftp_errno.h:56
#define kErrFileExistsButCannotDetermineType
Definition: ncftp_errno.h:107
#define kErrMLSTFailed
Definition: ncftp_errno.h:97
#define kErrHELPFailed
Definition: ncftp_errno.h:83
#define kErrSIZENotAvailable
Definition: ncftp_errno.h:65
#define kErrSIZEFailed
Definition: ncftp_errno.h:62
#define kErrUmaskFailed
Definition: ncftp_errno.h:60
#define kErrCannotGoToPrevDir
Definition: ncftp_errno.h:58
#define kErrNLSTFailed
Definition: ncftp_errno.h:103
#define kErrBadLineList
Definition: ncftp_errno.h:44
#define kErrRenameFailed
Definition: ncftp_errno.h:67
#define kErrCWDFailed
Definition: ncftp_errno.h:42
#define kErrSTATFailed
Definition: ncftp_errno.h:101
_Check_return_ _CRTIMP _CONST_RETURN char *__cdecl strrchr(_In_z_ const char *_Str, _In_ int _Ch)
_CRTIMP struct tm *__cdecl gmtime(const time_t *_Time)
Definition: time.h:415
int ietfCompatLevel
Definition: ncftp.h:233
int curTransferType
Definition: ncftp.h:157
char * startingWorkingDirectory
Definition: ncftp.h:158
char magic[16]
Definition: ncftp.h:135
int NLSTfileParamWorks
Definition: ncftp.h:180
int STATfileParamWorks
Definition: ncftp.h:179
size_t bufSize
Definition: ncftp.h:187
char lastFTPCmdResultStr[128]
Definition: ncftp.h:214
char * buf
Definition: ncftp.h:186
Definition: ncftp.h:84
int nLines
Definition: ncftp.h:86
LinePtr first
Definition: ncftp.h:85
LinePtr last
Definition: ncftp.h:85
Definition: ncftp.h:79
char * line
Definition: ncftp.h:81
LinePtr next
Definition: ncftp.h:80
longest_int fsize
Definition: ncftp.h:279
time_t ftime
Definition: ncftp.h:280
int ftype
Definition: ncftp.h:278
Definition: ncftp.h:89
int code
Definition: ncftp.h:92
LineList msg
Definition: ncftp.h:90
Definition: fci.c:127
Definition: time.h:68
int tm_mon
Definition: time.h:73
int tm_year
Definition: time.h:74
int tm_hour
Definition: time.h:71
int tm_sec
Definition: time.h:69
int tm_mday
Definition: time.h:72
int tm_min
Definition: time.h:70
#define snprintf
Definition: wintirpc.h:48