3 * Copyright (c) 1996-2001 Mike Gleason, NCEMRSoft.
10 #if defined(WIN32) || defined(_WINDOWS)
12 extern void GetSpecialDir(char *dst
, size_t size
, int whichDir
);
17 Realloc(void *ptr
, size_t siz
)
20 return (void *) malloc(siz
);
21 return ((void *) realloc(ptr
, siz
));
25 /* Use getcwd/getwd to get the full path of the current local
29 FTPGetLocalCWD(char *buf
, size_t size
)
32 static char *cwdBuf
= NULL
;
33 static size_t cwdBufSize
= 0;
35 if (cwdBufSize
== 0) {
36 cwdBufSize
= (size_t) 128;
37 cwdBuf
= (char *) malloc(cwdBufSize
);
45 if (getcwd(cwdBuf
, cwdBufSize
) != NULL
)
47 if (errno
!= ERANGE
) {
48 (void) Strncpy(buf
, ".", size
);
52 cwdBuf
= (char *) Realloc(cwdBuf
, cwdBufSize
);
55 return (Strncpy(buf
, cwdBuf
, size
));
58 static char *cwdBuf
= NULL
;
61 /* Due to the way getwd is usually implemented, it's
62 * important to have a buffer large enough to hold the
63 * whole thing. getwd usually starts at the end of the
64 * buffer, and works backwards, returning you a pointer
65 * to the beginning of it when it finishes.
67 if (size
< MAXPATHLEN
) {
68 /* Buffer not big enough, so use a temporary one,
69 * and then copy the first 'size' bytes of the
70 * temporary buffer to your 'buf.'
73 cwdBuf
= (char *) malloc((size_t) MAXPATHLEN
);
80 /* Buffer is big enough already. */
84 if (getwd(dp
) == NULL
) {
85 /* getwd() should write the reason why in the buffer then,
86 * according to the man pages.
88 (void) Strncpy(buf
, ".", size
);
91 return (Strncpy(buf
, dp
, size
));
93 #elif defined(WIN32) || defined(_WINDOWS)
94 if (GetCurrentDirectory((DWORD
) size
- 1, buf
) < 1)
99 /* Not a solution, but does anybody not have either of
109 /* Read a line, and axe the end-of-line. */
111 FGets(char *str
, size_t size
, FILE *fp
)
115 cp
= fgets(str
, ((int) size
) - 1, fp
);
117 cp
[((int) size
) - 1] = '\0'; /* ensure terminator */
118 nlptr
= cp
+ strlen(cp
) - 1;
122 memset(str
, 0, size
);
130 #if defined(WIN32) || defined(_WINDOWS)
132 int gettimeofday(struct timeval
*const tp
, void *junk
)
134 SYSTEMTIME systemTime
;
136 GetSystemTime(&systemTime
);
138 /* Create an arbitrary second counter;
139 * Note that this particular one creates
140 * a problem at the end of the month.
144 systemTime
.wMinute
* 60 +
145 systemTime
.wHour
* 3600 +
146 systemTime
.wDay
* 86400;
148 tp
->tv_usec
= systemTime
.wMilliseconds
* 1000;
158 #if defined(WIN32) || defined(_WINDOWS)
160 /* This looks up the user's password entry, trying to look by the username.
161 * We have a couple of extra hacks in place to increase the probability
162 * that we can get the username.
172 cp
= (char *) getenv("LOGNAME");
174 cp
= (char *) getenv("USER");
186 GetPass(const char *const prompt
)
189 return getpass(prompt
);
190 #elif defined(_CONSOLE) && (defined(WIN32) || defined(_WINDOWS))
191 static char pwbuf
[128];
195 (void) memset(pwbuf
, 0, sizeof(pwbuf
));
196 if (! _isatty(_fileno(stdout
)))
198 (void) fputs(prompt
, stdout
);
199 (void) fflush(stdout
);
201 for (dst
= pwbuf
, dlim
= dst
+ sizeof(pwbuf
) - 1;;) {
203 if ((c
== 0) || (c
== 0xe0)) {
204 /* The key is a function or arrow key; read and discard. */
207 if ((c
== '\r') || (c
== '\n'))
214 (void) fflush(stdout
);
215 (void) fflush(stdin
);
218 static char pwbuf
[128];
220 (void) memset(pwbuf
, 0, sizeof(pwbuf
));
221 #if defined(WIN32) || defined(_WINDOWS)
222 if (! _isatty(_fileno(stdout
)))
227 (void) fputs(prompt
, stdout
);
228 (void) fflush(stdout
);
229 (void) FGets(pwbuf
, sizeof(pwbuf
), stdin
);
230 (void) fflush(stdout
);
231 (void) fflush(stdin
);
240 GetHomeDir(char *dst
, size_t size
)
242 #if defined(WIN32) || defined(_WINDOWS)
243 const char *homedrive
, *homepath
;
245 homedrive
= getenv("HOMEDRIVE");
246 homepath
= getenv("HOMEPATH");
247 if ((homedrive
!= NULL
) && (homepath
!= NULL
)) {
248 (void) Strncpy(dst
, homedrive
, size
);
249 (void) Strncat(dst
, homepath
, size
);
253 // GetSpecialDir(dst, size, CSIDL_PERSONAL /* "My Documents" */);
254 // if (dst[0] != '\0')
258 // if (GetWindowsDirectory(dst, size - 1) < 1)
259 // (void) Strncpy(dst, ".", size);
260 // else if (dst[1] == ':') {
269 #if defined(USE_GETPWUID)
270 /* Try to use getpwuid(), but if we have to, fall back to getpwnam(). */
271 if ((pw
= getpwuid(getuid())) == NULL
)
272 pw
= GetPwByName(); /* Oh well, try getpwnam() then. */
274 /* Try to use getpwnam(), but if we have to, fall back to getpwuid(). */
275 if ((pw
= GetPwByName()) == NULL
)
276 pw
= getpwuid(getuid()); /* Try getpwnam() then. */
280 else if ((cp
= (const char *) getenv("LOGNAME")) == NULL
)
282 (void) Strncpy(dst
, cp
, size
);
290 GetUsrName(char *dst
, size_t size
)
292 #if defined(WIN32) || defined(_WINDOWS)
296 if (! GetUserName(dst
, &size1
))
297 (void) strncpy(dst
, "unknown", size
);
298 dst
[size
- 1] = '\0';
305 /* Try to use getpwuid(), but if we have to, fall back to getpwnam(). */
306 if ((pw
= getpwuid(getuid())) == NULL
)
307 pw
= GetPwByName(); /* Oh well, try getpwnam() then. */
309 /* Try to use getpwnam(), but if we have to, fall back to getpwuid(). */
310 if ((pw
= GetPwByName()) == NULL
)
311 pw
= getpwuid(getuid()); /* Try getpwnam() then. */
315 else if ((cp
= (const char *) getenv("LOGNAME")) == NULL
)
317 (void) Strncpy(dst
, cp
, size
);
325 /* Closes the file supplied, if it isn't a std stream. */
330 if ((*f
!= stdout
) && (*f
!= stdin
) && (*f
!= stderr
))
340 PrintF(const FTPCIPtr cip
, const char *const fmt
, ...)
346 if (cip
->debugLog
!= NULL
) {
347 (void) vfprintf(cip
->debugLog
, fmt
, ap
);
348 (void) fflush(cip
->debugLog
);
350 if (cip
->debugLogProc
!= NULL
) {
351 #ifdef HAVE_VSNPRINTF
352 (void) vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
353 buf
[sizeof(buf
) - 1] = '\0';
355 (void) vsprintf(buf
, fmt
, ap
);
357 (*cip
->debugLogProc
)(cip
, buf
);
368 Error(const FTPCIPtr cip
, const int pError
, const char *const fmt
, ...)
376 #ifndef HAVE_STRERROR
382 #ifdef HAVE_VSNPRINTF
383 vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
384 buf
[sizeof(buf
) - 1] = '\0';
386 (void) vsprintf(buf
, fmt
, ap
);
395 if (buf
[len
- 1] == '\n') {
398 if (buf
[len
- 2] == '.') {
402 } else if (buf
[len
- 1] == '.') {
408 (void) STRNCAT(buf
, ": ");
409 (void) STRNCAT(buf
, strerror(errnum
));
411 # ifdef HAVE_SNPRINTF
412 sprintf(errnostr
, sizeof(errnostr
) - 1, " (errno = %d)", errnum
);
413 errnostr
[sizeof(errnostr
) - 1] = '\0';
415 sprintf(errnostr
, " (errno = %d)", errnum
);
417 STRNCAT(buf
, errnostr
);
419 if (endsinperiod
!= 0)
420 (void) STRNCAT(buf
, ".");
421 if (endsinnewline
!= 0)
422 (void) STRNCAT(buf
, "\n");
425 if (cip
->errLog
!= NULL
) {
426 (void) fprintf(cip
->errLog
, "%s", buf
);
427 (void) fflush(cip
->errLog
);
429 if ((cip
->debugLog
!= NULL
) && (cip
->debugLog
!= cip
->errLog
)) {
430 if ((cip
->errLog
!= stderr
) || (cip
->debugLog
!= stdout
)) {
431 (void) fprintf(cip
->debugLog
, "%s", buf
);
432 (void) fflush(cip
->debugLog
);
435 if (cip
->errLogProc
!= NULL
) {
436 (*cip
->errLogProc
)(cip
, buf
);
438 if ((cip
->debugLogProc
!= NULL
) && (cip
->debugLogProc
!= cip
->errLogProc
)) {
439 (*cip
->debugLogProc
)(cip
, buf
);
446 /* Cheezy, but somewhat portable way to get GMT offset. */
449 time_t GetUTCOffset(int mon
, int mday
)
451 struct tm local_tm
, utc_tm
, *utc_tmptr
;
452 time_t local_t
, utc_t
, utcOffset
;
458 local_tm
.tm_year
= 94; /* Doesn't really matter. */
459 local_tm
.tm_mon
= mon
;
460 local_tm
.tm_mday
= mday
;
461 local_tm
.tm_hour
= 12;
462 local_tm
.tm_isdst
= -1;
463 local_t
= mktime(&local_tm
);
465 if (local_t
!= (time_t) -1) {
466 utc_tmptr
= gmtime(&local_t
);
467 utc_tm
.tm_year
= utc_tmptr
->tm_year
;
468 utc_tm
.tm_mon
= utc_tmptr
->tm_mon
;
469 utc_tm
.tm_mday
= utc_tmptr
->tm_mday
;
470 utc_tm
.tm_hour
= utc_tmptr
->tm_hour
;
471 utc_tm
.tm_isdst
= -1;
472 utc_t
= mktime(&utc_tm
);
474 if (utc_t
!= (time_t) -1)
475 utcOffset
= (local_t
- utc_t
);
479 #endif /* HAVE_MKTIME */
483 /* Converts a MDTM date, like "19930602204445"
484 * format to a time_t.
486 time_t UnMDTMDate(char *dstr
)
489 return (kModTimeUnknown
);
493 time_t result
= kModTimeUnknown
;
495 if (strncmp(dstr
, "19100", 5) == 0) {
496 /* Server Y2K bug! */
503 /* Copy the whole structure of the 'tm' pointed to by t, so it will
504 * also set all fields we don't specify explicitly to be the same as
505 * they were in t. That way we copy non-standard fields such as
506 * tm_gmtoff, if it exists or not.
510 /* The time we get back from the server is (should be) in UTC. */
511 if (sscanf(dstr
, "%04d%02d%02d%02d%02d%02d",
522 if (mt
!= (time_t) -1) {
523 mt
+= GetUTCOffset(ut
.tm_mon
, ut
.tm_mday
);
524 result
= (time_t) mt
;
528 #endif /* HAVE_MKTIME */
534 GetSockBufSize(int sockfd
, size_t *rsize
, size_t *ssize
)
543 optsize
= sizeof(opt
);
544 rc
= getsockopt(sockfd
, SOL_SOCKET
, SO_SNDBUF
, (char *) &opt
, &optsize
);
546 *ssize
= (size_t) opt
;
552 optsize
= sizeof(opt
);
553 rc
= getsockopt(sockfd
, SOL_SOCKET
, SO_RCVBUF
, (char *) &opt
, &optsize
);
555 *rsize
= (size_t) opt
;
567 } /* GetSockBufSize */
572 SetSockBufSize(int sockfd
, size_t rsize
, size_t ssize
)
580 /* This is an AIX-specific socket option to do RFC1323 large windows */
581 if (ssize
> 0 || rsize
> 0) {
583 optsize
= sizeof(opt
);
584 rc
= setsockopt(sockfd
, IPPROTO_TCP
, TCP_RFC1323
, &opt
, optsize
);
590 optsize
= sizeof(opt
);
591 rc
= setsockopt(sockfd
, SOL_SOCKET
, SO_SNDBUF
, (char *) &opt
, optsize
);
595 optsize
= sizeof(opt
);
596 rc
= setsockopt(sockfd
, SOL_SOCKET
, SO_RCVBUF
, (char *) &opt
, optsize
);
602 } /* SetSockBufSize */
607 Scramble(unsigned char *dst
, size_t dsize
, unsigned char *src
, char *key
)
614 keyLen
= strlen(key
);
615 k2
= (unsigned char *) key
;
616 for (i
=0; i
< (int) dsize
- 1; i
++) {
620 dst
[i
] = (unsigned char) (ch
^ (int) (k2
[i
% (int) keyLen
]));
629 #if defined(WIN32) || defined(_WINDOWS)
630 void WinSleep(unsigned int seconds
)
633 DWORD milliseconds
= seconds
* 1000;
635 if (milliseconds
> 0) {
636 now
= GetTickCount();
637 deadline
= now
+ milliseconds
;
638 if (now
< deadline
) {
641 milliseconds
= deadline
- now
;
643 now
= GetTickCount();
644 } while (now
< deadline
);
648 milliseconds
-= (0xFFFFFFFF - now
);
650 Sleep(0xFFFFFFFF - now
);
651 now
= GetTickCount();
652 } while (now
> deadline
);
653 /* Counter has now wrapped around */
654 deadline
= now
+ milliseconds
;
656 milliseconds
= deadline
- now
;
658 now
= GetTickCount();
659 } while (now
< deadline
);
668 StrFindLocalPathDelim(const char *src
) /* TODO: optimize */
678 if (IsLocalPathDelim(c
)) {
684 return ((char *) first
);
685 } /* StrFindLocalPathDelim */
690 StrRFindLocalPathDelim(const char *src
) /* TODO: optimize */
700 if (IsLocalPathDelim(c
))
704 return ((char *) last
);
705 } /* StrRFindLocalPathDelim */
711 StrRemoveTrailingLocalPathDelim(char *dst
)
715 cp
= StrRFindLocalPathDelim(dst
);
716 if ((cp
== NULL
) || (cp
[1] != '\0'))
719 /* Note: Do not destroy a path of "/" */
720 while ((cp
> dst
) && (IsLocalPathDelim(*cp
)))
722 } /* StrRemoveTrailingLocalPathDelim */
727 TVFSPathToLocalPath(char *dst
)
731 /* Note: Technically we don't need to do this,
732 * since Win32 accepts a / as equivalent to a \
741 dst
[-1] = LOCAL_PATH_DELIM
;
744 } /* TVFSPathToLocalPath */
748 LocalPathToTVFSPath(char *dst
)
757 if (c
== LOCAL_PATH_DELIM
)
761 } /* LocalPathToTVFSPath */
768 StrRemoveTrailingSlashes(char *dst
)
772 cp
= strrchr(dst
, '/');
773 if ((cp
== NULL
) || (cp
[1] != '\0'))
776 /* Note: Do not destroy a path of "/" */
777 while ((cp
> dst
) && (*cp
== '/'))
779 } /* StrRemoveTrailingSlashes */
785 MkDirs(const char *const newdir
, int mode1
)
790 #if defined(WIN32) || defined(_WINDOWS)
795 mode_t mode
= (mode_t
) mode1
;
798 #if defined(WIN32) || defined(_WINDOWS)
799 if ((isalpha(newdir
[0])) && (newdir
[1] == ':')) {
800 if (! IsLocalPathDelim(newdir
[2])) {
801 /* Special case "c:blah", and errout.
802 * "c:\blah" must be used or _access GPFs.
806 } else if (newdir
[3] == '\0') {
807 /* Special case root directory, which cannot be made. */
810 } else if (IsUNCPrefixed(newdir
)) {
811 share
= StrFindLocalPathDelim(newdir
+ 2);
812 if ((share
== NULL
) || (StrFindLocalPathDelim(share
+ 1) == NULL
))
816 if (_access(newdir
, 00) == 0) {
817 if (_stat(newdir
, &st
) < 0)
819 if (! S_ISDIR(st
.st_mode
)) {
826 if (access(newdir
, F_OK
) == 0) {
827 if (Stat(newdir
, &st
) < 0)
829 if (! S_ISDIR(st
.st_mode
)) {
837 (void) strncpy(s
, newdir
, sizeof(s
));
838 if (s
[sizeof(s
) - 1] != '\0') {
840 errno
= ENAMETOOLONG
;
847 cp
= StrRFindLocalPathDelim(s
);
849 #if defined(WIN32) || defined(_WINDOWS)
850 if (! CreateDirectory(newdir
, (LPSECURITY_ATTRIBUTES
) 0))
854 rc
= mkdir(newdir
, mode
);
857 } else if (cp
[1] == '\0') {
858 /* Remove trailing slashes from path. */
861 if (! IsLocalPathDelim(*cp
))
866 cp
= StrRFindLocalPathDelim(s
);
868 #if defined(WIN32) || defined(_WINDOWS)
869 if (! CreateDirectory(s
, (LPSECURITY_ATTRIBUTES
) 0))
878 /* Find the deepest directory in this
879 * path that already exists. When
880 * we do, we want to have the 's'
881 * string as it was originally, but
882 * with 'cp' pointing to the first
883 * slash in the path that starts the
884 * part that does not exist.
889 #if defined(WIN32) || defined(_WINDOWS)
892 rc
= access(s
, F_OK
);
895 *sl
= LOCAL_PATH_DELIM
;
897 *cp
= LOCAL_PATH_DELIM
;
901 cp
= StrRFindLocalPathDelim(s
);
903 /* We do not have any more
904 * slashes, so none of the
905 * new directory's components
906 * existed before, so we will
907 * have to make everything
908 * starting at the first node.
911 *sl
= LOCAL_PATH_DELIM
;
913 /* We refer to cp + 1 below,
914 * so this is why we can
915 * set "cp" to point to the
916 * byte before the array starts.
924 /* Extend the path we have to
925 * include the next component
928 sl
= StrFindLocalPathDelim(cp
+ 1);
930 /* If the next slash is pointing
931 * to the start of the string, then
932 * the path is an absolute path and
933 * we don't need to make the root node,
934 * and besides the next mkdir would
935 * try an empty string.
938 sl
= StrFindLocalPathDelim(cp
+ 1);
943 #if defined(WIN32) || defined(_WINDOWS)
944 if (! CreateDirectory(s
, (LPSECURITY_ATTRIBUTES
) 0))
953 *sl
= LOCAL_PATH_DELIM
;
963 FilenameExtensionIndicatesASCII(const char *const pathName
, const char *const extnList
)
968 char extnPattern
[16];
970 extn
= pathName
+ strlen(pathName
) - 1;
972 if (extn
<= pathName
)
973 return (0); /* End of pathname, no extension. */
975 if (IsLocalPathDelim(c
))
976 return (0); /* End of filename, no extension. */
982 if (strlen(extn
) > (sizeof(extnPattern
) - 2 - 1 - 1)) {
986 snprintf(extnPattern
, sizeof(extnPattern
),
1007 /* Extension list is specially formatted, like this:
1009 * |ext1|ext2|ext3|...|extN|
1011 * I.e, each filename extension is delimited with
1012 * a pipe, and we always begin and end the string
1015 if (strstr(extnList
, extnPattern
) != NULL
) {
1019 } /* FilenameExtensionIndicatesASCII */
1025 #ifdef HAVE_SIGACTION
1026 void (*NcSignal(int signum
, void (*handler
)(int)))(int)
1028 struct sigaction sa
, osa
;
1030 (void) sigemptyset(&sa
.sa_mask
);
1032 sa
.sa_handler
= handler
;
1033 if (signum
== SIGALRM
) {
1035 sa
.sa_flags
|= SA_INTERRUPT
;
1039 sa
.sa_flags
|= SA_RESTART
;
1042 if (sigaction(signum
, &sa
, &osa
) < 0)
1043 return ((FTPSigProc
) SIG_ERR
);
1044 return (osa
.sa_handler
);
1046 #endif /* HAVE_SIGACTION */