1 /* util.c
2  *
3  * Copyright (c) 1996-2001 Mike Gleason, NCEMRSoft.
4  * All rights reserved.
5  *
6  */
7 
8 #include "syshdrs.h"
9 
10 #if defined(WIN32) || defined(_WINDOWS)
11 #include <conio.h>
12 extern void GetSpecialDir(char *dst, size_t size, int whichDir);
13 #endif
14 
15 
16 /* static void *
17 Realloc(void *ptr, size_t siz)
18 {
19 	if (ptr == NULL)
20 		return (void *) malloc(siz);
21 	return ((void *) realloc(ptr, siz));
22 }*/
23 
24 
25 /* Use getcwd/getwd to get the full path of the current local
26  * working directory.
27  */
28 char *
29 FTPGetLocalCWD(char *buf, size_t size)
30 {
31 #ifdef HAVE_GETCWD
32 	static char *cwdBuf = NULL;
33 	static size_t cwdBufSize = 0;
34 
35 	if (cwdBufSize == 0) {
36 		cwdBufSize = (size_t) 128;
37 		cwdBuf = (char *) malloc(cwdBufSize);
38 	}
39 
40 	for (errno = 0; ; ) {
41 		if (cwdBuf == NULL) {
42 			return NULL;
43 		}
44 
45 		if (getcwd(cwdBuf, cwdBufSize) != NULL)
46 			break;
47 		if (errno != ERANGE) {
48 			(void) Strncpy(buf, ".", size);
49 			return NULL;
50 		}
51 		cwdBufSize *= 2;
52 		cwdBuf = (char *) Realloc(cwdBuf, cwdBufSize);
53 	}
54 
55 	return (Strncpy(buf, cwdBuf, size));
56 #else
57 #ifdef HAVE_GETWD
58 	static char *cwdBuf = NULL;
59 	char *dp;
60 
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.
66 	 */
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.'
71 		 */
72 		if (cwdBuf == NULL) {
73 			cwdBuf = (char *) malloc((size_t) MAXPATHLEN);
74 			if (cwdBuf == NULL) {
75 				return NULL;
76 			}
77 		}
78 		dp = cwdBuf;
79 	} else {
80 		/* Buffer is big enough already. */
81 		dp = buf;
82 	}
83 	*dp = '\0';
84 	if (getwd(dp) == NULL) {
85 		/* getwd() should write the reason why in the buffer then,
86 		 * according to the man pages.
87 		 */
88 		(void) Strncpy(buf, ".", size);
89 		return (NULL);
90 	}
91 	return (Strncpy(buf, dp, size));
92 
93 #elif defined(WIN32) || defined(_WINDOWS)
94 	if (GetCurrentDirectory((DWORD) size - 1, buf) < 1)
95 		return NULL;
96 	buf[size - 1] = '\0';
97 	return buf;
98 #else
99 	/* Not a solution, but does anybody not have either of
100 	 * getcwd or getwd?
101 	 */
102 	--Error--;
103 #endif
104 #endif
105 }   /* GetCWD */
106 
107 
108 
109 /* Read a line, and axe the end-of-line. */
110 char *
111 FGets(char *str, size_t size, FILE *fp)
112 {
113 	char *cp, *nlptr;
114 
115 	cp = fgets(str, ((int) size) - 1, fp);
116 	if (cp != NULL) {
117 		cp[((int) size) - 1] = '\0';	/* ensure terminator */
118 		nlptr = cp + strlen(cp) - 1;
119 		if (*nlptr == '\n')
120 			*nlptr = '\0';
121 	} else {
122 		memset(str, 0, size);
123 	}
124 	return cp;
125 }	/* FGets */
126 
127 
128 
129 
130 #if defined(WIN32) || defined(_WINDOWS)
131 
132 int gettimeofday(struct timeval *const tp, void *junk)
133 {
134 	SYSTEMTIME systemTime;
135 
136 	GetSystemTime(&systemTime);
137 
138 	/* Create an arbitrary second counter;
139 	 * Note that this particular one creates
140 	 * a problem at the end of the month.
141 	 */
142 	tp->tv_sec =
143 		systemTime.wSecond +
144 		systemTime.wMinute * 60 +
145 		systemTime.wHour * 3600 +
146 		systemTime.wDay * 86400;
147 
148 	tp->tv_usec = systemTime.wMilliseconds * 1000;
149 
150 	return 0;
151 }	/* gettimeofday */
152 
153 #endif
154 
155 
156 
157 
158 #if defined(WIN32) || defined(_WINDOWS)
159 #else
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.
163  */
164 struct passwd *
165 GetPwByName(void)
166 {
167 	char *cp;
168 	struct passwd *pw;
169 
170 	cp = getlogin();
171 	if (cp == NULL) {
172 		cp = (char *) getenv("LOGNAME");
173 		if (cp == NULL)
174 			cp = (char *) getenv("USER");
175 	}
176 	pw = NULL;
177 	if (cp != NULL)
178 		pw = getpwnam(cp);
179 	return (pw);
180 }	/* GetPwByName */
181 #endif
182 
183 
184 
185 char *
186 GetPass(const char *const prompt)
187 {
188 #ifdef HAVE_GETPASS
189 	return getpass(prompt);
190 #elif defined(_CONSOLE) && (defined(WIN32) || defined(_WINDOWS))
191 	static char pwbuf[128];
192 	char *dst, *dlim;
193 	int c;
194 
195 	(void) memset(pwbuf, 0, sizeof(pwbuf));
196 	if (! _isatty(_fileno(stdout)))
197 		return (pwbuf);
198 	(void) fputs(prompt, stdout);
199 	(void) fflush(stdout);
200 
201 	for (dst = pwbuf, dlim = dst + sizeof(pwbuf) - 1;;) {
202 		c = _getch();
203 		if ((c == 0) || (c == 0xe0)) {
204 			/* The key is a function or arrow key; read and discard. */
205 			(void) _getch();
206 		}
207 		if ((c == '\r') || (c == '\n'))
208 			break;
209 		if (dst < dlim)
210 			*dst++ = c;
211 	}
212 	*dst = '\0';
213 
214 	(void) fflush(stdout);
215 	(void) fflush(stdin);
216 	return (pwbuf);
217 #else
218 	static char pwbuf[128];
219 
220 	(void) memset(pwbuf, 0, sizeof(pwbuf));
221 #if defined(WIN32) || defined(_WINDOWS)
222 	if (! _isatty(_fileno(stdout)))
223 #else
224 	if (! isatty(1))
225 #endif
226 		return (pwbuf);
227 	(void) fputs(prompt, stdout);
228 	(void) fflush(stdout);
229 	(void) FGets(pwbuf, sizeof(pwbuf), stdin);
230 	(void) fflush(stdout);
231 	(void) fflush(stdin);
232 	return (pwbuf);
233 #endif
234 }	/* GetPass */
235 
236 
237 
238 
239 void
240 GetHomeDir(char *dst, size_t size)
241 {
242 #if defined(WIN32) || defined(_WINDOWS)
243 	const char *homedrive, *homepath;
244 
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);
250 		return;
251 	}
252 
253 //	GetSpecialDir(dst, size, CSIDL_PERSONAL	/* "My Documents" */);
254 //	if (dst[0] != '\0')
255 //		return;
256 //
257 //	dst[0] = '\0';
258 //	if (GetWindowsDirectory(dst, size - 1) < 1)
259 //		(void) Strncpy(dst, ".", size);
260 //	else if (dst[1] == ':') {
261 //		dst[2] = '\\';
262 //		dst[3] = '\0';
263 //	}
264 #else
265 	const char *cp;
266 	struct passwd *pw;
267 
268 	pw = NULL;
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. */
273 #else
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. */
277 #endif
278 	if (pw != NULL)
279 		cp = pw->pw_dir;
280 	else if ((cp = (const char *) getenv("LOGNAME")) == NULL)
281 			cp = ".";
282 	(void) Strncpy(dst, cp, size);
283 #endif
284 }	/* GetHomeDir */
285 
286 
287 
288 
289 void
290 GetUsrName(char *dst, size_t size)
291 {
292 #if defined(WIN32) || defined(_WINDOWS)
293 	DWORD size1;
294 
295 	size1 = size - 1;
296 	if (! GetUserName(dst, &size1))
297 		(void) strncpy(dst, "unknown", size);
298 	dst[size - 1] = '\0';
299 #else
300 	const char *cp;
301 	struct passwd *pw;
302 
303 	pw = NULL;
304 #ifdef USE_GETPWUID
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. */
308 #else
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. */
312 #endif
313 	if (pw != NULL)
314 		cp = pw->pw_name;
315 	else if ((cp = (const char *) getenv("LOGNAME")) == NULL)
316 			cp = "UNKNOWN";
317 	(void) Strncpy(dst, cp, size);
318 #endif
319 }	/* GetUserName */
320 
321 
322 
323 
324 
325 /* Closes the file supplied, if it isn't a std stream. */
326 void
327 CloseFile(FILE **f)
328 {
329 	if (*f != NULL) {
330 		if ((*f != stdout) && (*f != stdin) && (*f != stderr))
331 			(void) fclose(*f);
332 		*f = NULL;
333 	}
334 }	/* CloseFile */
335 
336 
337 
338 /*VARARGS*/
339 void
340 PrintF(const FTPCIPtr cip, const char *const fmt, ...)
341 {
342 	va_list ap;
343 	char buf[256];
344 
345 	va_start(ap, fmt);
346 	if (cip->debugLog != NULL) {
347 		(void) vfprintf(cip->debugLog, fmt, ap);
348 		(void) fflush(cip->debugLog);
349 	}
350 	if (cip->debugLogProc != NULL) {
351 #ifdef HAVE_VSNPRINTF
352 		(void) vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
353 		buf[sizeof(buf) - 1] = '\0';
354 #else
355 		(void) vsprintf(buf, fmt, ap);
356 #endif
357 		(*cip->debugLogProc)(cip, buf);
358 	}
359 	va_end(ap);
360 }	/* PrintF */
361 
362 
363 
364 
365 
366 /*VARARGS*/
367 void
368 Error(const FTPCIPtr cip, const int pError, const char *const fmt, ...)
369 {
370 	va_list ap;
371 	int errnum;
372 	size_t len;
373 	char buf[256];
374 	int endsinperiod;
375 	int endsinnewline;
376 #ifndef HAVE_STRERROR
377 	char errnostr[16];
378 #endif
379 
380 	errnum = errno;
381 	va_start(ap, fmt);
382 #ifdef HAVE_VSNPRINTF
383 	vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
384 	buf[sizeof(buf) - 1] = '\0';
385 #else
386 	(void) vsprintf(buf, fmt, ap);
387 #endif
388 	va_end(ap);
389 
390 	if (pError != 0) {
391 		len = strlen(buf);
392 		endsinperiod = 0;
393 		endsinnewline = 0;
394 		if (len > 2) {
395 			if (buf[len - 1] == '\n') {
396 				endsinnewline = 1;
397 				buf[len - 1] = '\0';
398 				if (buf[len - 2] == '.') {
399 					endsinperiod = 1;
400 					buf[len - 2] = '\0';
401 				}
402 			} else if (buf[len - 1] == '.') {
403 				endsinperiod = 1;
404 				buf[len - 1] = '\0';
405 			}
406 		}
407 #ifdef HAVE_STRERROR
408 		(void) STRNCAT(buf, ": ");
409 		(void) STRNCAT(buf, strerror(errnum));
410 #else
411 #	ifdef HAVE_SNPRINTF
412 		sprintf(errnostr, sizeof(errnostr) - 1, " (errno = %d)", errnum);
413 		errnostr[sizeof(errnostr) - 1] = '\0';
414 #	else
415 		sprintf(errnostr, " (errno = %d)", errnum);
416 #	endif
417 		STRNCAT(buf, errnostr);
418 #endif
419 		if (endsinperiod != 0)
420 			(void) STRNCAT(buf, ".");
421 		if (endsinnewline != 0)
422 			(void) STRNCAT(buf, "\n");
423 	}
424 
425 	if (cip->errLog != NULL) {
426 		(void) fprintf(cip->errLog, "%s", buf);
427 		(void) fflush(cip->errLog);
428 	}
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);
433 		}
434 	}
435 	if (cip->errLogProc != NULL) {
436 		(*cip->errLogProc)(cip, buf);
437 	}
438 	if ((cip->debugLogProc != NULL) && (cip->debugLogProc != cip->errLogProc)) {
439 		(*cip->debugLogProc)(cip, buf);
440 	}
441 }	/* Error */
442 
443 
444 
445 
446 /* Cheezy, but somewhat portable way to get GMT offset. */
447 #ifdef HAVE_MKTIME
448 static
449 time_t GetUTCOffset(int mon, int mday)
450 {
451 	struct tm local_tm, utc_tm, *utc_tmptr;
452 	time_t local_t, utc_t, utcOffset;
453 
454 	ZERO(local_tm);
455 	ZERO(utc_tm);
456 	utcOffset = 0;
457 
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);
464 
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);
473 
474 		if (utc_t != (time_t) -1)
475 			utcOffset = (local_t - utc_t);
476 	}
477 	return (utcOffset);
478 }	/* GetUTCOffset */
479 #endif	/* HAVE_MKTIME */
480 
481 
482 
483 /* Converts a MDTM date, like "19930602204445"
484  * format to a time_t.
485  */
486 time_t UnMDTMDate(char *dstr)
487 {
488 #ifndef HAVE_MKTIME
489 	return (kModTimeUnknown);
490 #else
491 	struct tm ut, *t;
492 	time_t mt, now;
493 	time_t result = kModTimeUnknown;
494 
495 	if (strncmp(dstr, "19100", 5) == 0) {
496 		/* Server Y2K bug! */
497 		return (result);
498 	}
499 
500 	(void) time(&now);
501 	t = localtime(&now);
502 
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.
507 	 */
508 	ut = *t;
509 
510 	/* The time we get back from the server is (should be) in UTC. */
511 	if (sscanf(dstr, "%04d%02d%02d%02d%02d%02d",
512 		&ut.tm_year,
513 		&ut.tm_mon,
514 		&ut.tm_mday,
515 		&ut.tm_hour,
516 		&ut.tm_min,
517 		&ut.tm_sec) == 6)
518 	{
519 		--ut.tm_mon;
520 		ut.tm_year -= 1900;
521 		mt = mktime(&ut);
522 		if (mt != (time_t) -1) {
523 			mt += GetUTCOffset(ut.tm_mon, ut.tm_mday);
524 			result = (time_t) mt;
525 		}
526 	}
527 	return result;
528 #endif	/* HAVE_MKTIME */
529 }	/* UnMDTMDate */
530 
531 
532 
533 int
534 GetSockBufSize(int sockfd, size_t *rsize, size_t *ssize)
535 {
536 #ifdef SO_SNDBUF
537 	int rc = -1;
538 	int opt;
539 	int optsize;
540 
541 	if (ssize != NULL) {
542 		opt = 0;
543 		optsize = sizeof(opt);
544 		rc = getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *) &opt, &optsize);
545 		if (rc == 0)
546 			*ssize = (size_t) opt;
547 		else
548 			*ssize = 0;
549 	}
550 	if (rsize != NULL) {
551 		opt = 0;
552 		optsize = sizeof(opt);
553 		rc = getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (char *) &opt, &optsize);
554 		if (rc == 0)
555 			*rsize = (size_t) opt;
556 		else
557 			*rsize = 0;
558 	}
559 	return (rc);
560 #else
561 	if (ssize != NULL)
562 		*ssize = 0;
563 	if (rsize != NULL)
564 		*rsize = 0;
565 	return (-1);
566 #endif
567 }	/* GetSockBufSize */
568 
569 
570 
571 int
572 SetSockBufSize(int sockfd, size_t rsize, size_t ssize)
573 {
574 #ifdef SO_SNDBUF
575 	int rc = -1;
576 	int opt;
577 	int optsize;
578 
579 #ifdef TCP_RFC1323
580 	/* This is an AIX-specific socket option to do RFC1323 large windows */
581 	if (ssize > 0 || rsize > 0) {
582 		opt = 1;
583 		optsize = sizeof(opt);
584 		rc = setsockopt(sockfd, IPPROTO_TCP, TCP_RFC1323, &opt, optsize);
585 	}
586 #endif
587 
588 	if (ssize > 0) {
589 		opt = (int) ssize;
590 		optsize = sizeof(opt);
591 		rc = setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *) &opt, optsize);
592 	}
593 	if (rsize > 0) {
594 		opt = (int) rsize;
595 		optsize = sizeof(opt);
596 		rc = setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (char *) &opt, optsize);
597 	}
598 	return (rc);
599 #else
600 	return (-1);
601 #endif
602 }	/* SetSockBufSize */
603 
604 
605 
606 void
607 Scramble(unsigned char *dst, size_t dsize, unsigned char *src, char *key)
608 {
609 	int i;
610 	unsigned int ch;
611 	unsigned char *k2;
612 	size_t keyLen;
613 
614 	keyLen = strlen(key);
615 	k2 = (unsigned char *) key;
616 	for (i=0; i < (int) dsize - 1; i++) {
617 		ch = src[i];
618 		if (ch == 0)
619 			break;
620 		dst[i] = (unsigned char) (ch ^ (int) (k2[i % (int) keyLen]));
621 	}
622 	dst[i] = '\0';
623 }	/* Scramble */
624 
625 
626 
627 
628 
629 #if defined(WIN32) || defined(_WINDOWS)
630 void WinSleep(unsigned int seconds)
631 {
632 	DWORD now, deadline;
633 	DWORD milliseconds = seconds * 1000;
634 
635 	if (milliseconds > 0) {
636 		now = GetTickCount();
637 		deadline = now + milliseconds;
638 		if (now < deadline) {
639 			/* Typical case */
640 			do {
641 				milliseconds = deadline - now;
642 				Sleep(milliseconds);
643 				now = GetTickCount();
644 			} while (now < deadline);
645 		} else {
646 			/* Overflow case */
647 			deadline = now - 1;
648 			milliseconds -= (0xFFFFFFFF - now);
649 			do {
650 				Sleep(0xFFFFFFFF - now);
651 				now = GetTickCount();
652 			} while (now > deadline);
653 			/* Counter has now wrapped around */
654 			deadline = now + milliseconds;
655 			do {
656 				milliseconds = deadline - now;
657 				Sleep(milliseconds);
658 				now = GetTickCount();
659 			} while (now < deadline);
660 		}
661 	}
662 }	/* WinSleep */
663 
664 
665 
666 
667 char *
668 StrFindLocalPathDelim(const char *src) /* TODO: optimize */
669 {
670 	const char *first;
671 	int c;
672 
673 	first = NULL;
674 	for (;;) {
675 		c = *src++;
676 		if (c == '\0')
677 			break;
678 		if (IsLocalPathDelim(c)) {
679 			first = src - 1;
680 			break;
681 		}
682 	}
683 
684 	return ((char *) first);
685 }	/* StrFindLocalPathDelim */
686 
687 
688 
689 char *
690 StrRFindLocalPathDelim(const char *src)	/* TODO: optimize */
691 {
692 	const char *last;
693 	int c;
694 
695 	last = NULL;
696 	for (;;) {
697 		c = *src++;
698 		if (c == '\0')
699 			break;
700 		if (IsLocalPathDelim(c))
701 			last = src - 1;
702 	}
703 
704 	return ((char *) last);
705 }	/* StrRFindLocalPathDelim */
706 
707 
708 
709 
710 void
711 StrRemoveTrailingLocalPathDelim(char *dst)
712 {
713 	char *cp;
714 
715 	cp = StrRFindLocalPathDelim(dst);
716 	if ((cp == NULL) || (cp[1] != '\0'))
717 		return;
718 
719 	/* Note: Do not destroy a path of "/" */
720 	while ((cp > dst) && (IsLocalPathDelim(*cp)))
721 		*cp-- = '\0';
722 }	/* StrRemoveTrailingLocalPathDelim */
723 
724 
725 
726 void
727 TVFSPathToLocalPath(char *dst)
728 {
729 	int c;
730 
731 	/* Note: Technically we don't need to do this,
732 	 * since Win32 accepts a / as equivalent to a \
733 	 * in a pathname.
734 	 */
735 	if (dst != NULL) {
736 		for (;;) {
737 			c = *dst++;
738 			if (c == '\0')
739 				break;
740 			if (c == '/')
741 				dst[-1] = LOCAL_PATH_DELIM;
742 		}
743 	}
744 }	/* TVFSPathToLocalPath */
745 
746 
747 void
748 LocalPathToTVFSPath(char *dst)
749 {
750 	int c;
751 
752 	if (dst != NULL) {
753 		for (;;) {
754 			c = *dst++;
755 			if (c == '\0')
756 				break;
757 			if (c == LOCAL_PATH_DELIM)
758 				dst[-1] = '/';
759 		}
760 	}
761 }	/* LocalPathToTVFSPath */
762 #endif		/* WINDOWS */
763 
764 
765 
766 
767 void
768 StrRemoveTrailingSlashes(char *dst)
769 {
770 	char *cp;
771 
772 	cp = strrchr(dst, '/');
773 	if ((cp == NULL) || (cp[1] != '\0'))
774 		return;
775 
776 	/* Note: Do not destroy a path of "/" */
777 	while ((cp > dst) && (*cp == '/'))
778 		*cp-- = '\0';
779 }	/* StrRemoveTrailingSlashes */
780 
781 
782 
783 
784 int
785 MkDirs(const char *const newdir, int mode1)
786 {
787 	char s[512];
788 	int rc;
789 	char *cp, *sl;
790 #if defined(WIN32) || defined(_WINDOWS)
791 	struct _stat st;
792 	char *share;
793 #else
794 	struct Stat st;
795 	mode_t mode = (mode_t) mode1;
796 #endif
797 
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.
803 			 */
804 			errno = EINVAL;
805 			return (-1);
806 		} else if (newdir[3] == '\0') {
807 			/* Special case root directory, which cannot be made. */
808 			return (0);
809 		}
810 	} else if (IsUNCPrefixed(newdir)) {
811 		share = StrFindLocalPathDelim(newdir + 2);
812 		if ((share == NULL) || (StrFindLocalPathDelim(share + 1) == NULL))
813 			return (-1);
814 	}
815 
816 	if (_access(newdir, 00) == 0) {
817 		if (_stat(newdir, &st) < 0)
818 			return (-1);
819 		if (! S_ISDIR(st.st_mode)) {
820 			errno = ENOTDIR;
821 			return (-1);
822 		}
823 		return 0;
824 	}
825 #else
826 	if (access(newdir, F_OK) == 0) {
827 		if (Stat(newdir, &st) < 0)
828 			return (-1);
829 		if (! S_ISDIR(st.st_mode)) {
830 			errno = ENOTDIR;
831 			return (-1);
832 		}
833 		return 0;
834 	}
835 #endif
836 
837 	(void) strncpy(s, newdir, sizeof(s));
838 	if (s[sizeof(s) - 1] != '\0') {
839 #ifdef ENAMETOOLONG
840 		errno = ENAMETOOLONG;
841 #else
842 		errno = EINVAL;
843 		return (-1);
844 #endif
845 	}
846 
847 	cp = StrRFindLocalPathDelim(s);
848 	if (cp == NULL) {
849 #if defined(WIN32) || defined(_WINDOWS)
850 		if (! CreateDirectory(newdir, (LPSECURITY_ATTRIBUTES) 0))
851 			return (-1);
852 		return (0);
853 #else
854 		rc = mkdir(newdir, mode);
855 		return (rc);
856 #endif
857 	} else if (cp[1] == '\0') {
858 		/* Remove trailing slashes from path. */
859 		--cp;
860 		while (cp > s) {
861 			if (! IsLocalPathDelim(*cp))
862 				break;
863 			--cp;
864 		}
865 		cp[1] = '\0';
866 		cp = StrRFindLocalPathDelim(s);
867 		if (cp == NULL) {
868 #if defined(WIN32) || defined(_WINDOWS)
869 			if (! CreateDirectory(s, (LPSECURITY_ATTRIBUTES) 0))
870 				return (-1);
871 #else
872 			rc = mkdir(s, mode);
873 			return (rc);
874 #endif
875 		}
876 	}
877 
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.
885 	 */
886 	sl = NULL;
887 	for (;;) {
888 		*cp = '\0';
889 #if defined(WIN32) || defined(_WINDOWS)
890 		rc = _access(s, 00);
891 #else
892 		rc = access(s, F_OK);
893 #endif
894 		if (sl != NULL)
895 			*sl = LOCAL_PATH_DELIM;
896 		if (rc == 0) {
897 			*cp = LOCAL_PATH_DELIM;
898 			break;
899 		}
900 		sl = cp;
901 		cp = StrRFindLocalPathDelim(s);
902 		if (cp == NULL) {
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.
909 			 */
910 			if (sl != NULL)
911 				*sl = LOCAL_PATH_DELIM;
912 
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.
917 			 */
918 			cp = s - 1;
919 			break;
920 		}
921 	}
922 
923 	for (;;) {
924 		/* Extend the path we have to
925 		 * include the next component
926 		 * to make.
927 		 */
928 		sl = StrFindLocalPathDelim(cp + 1);
929 		if (sl == s) {
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.
936 			 */
937 			++cp;
938 			sl = StrFindLocalPathDelim(cp + 1);
939 		}
940 		if (sl != NULL) {
941 			*sl = '\0';
942 		}
943 #if defined(WIN32) || defined(_WINDOWS)
944 		if (! CreateDirectory(s, (LPSECURITY_ATTRIBUTES) 0))
945 			return (-1);
946 #else
947 		rc = mkdir(s, mode);
948 		if (rc < 0)
949 			return rc;
950 #endif
951 		if (sl == NULL)
952 			break;
953 		*sl = LOCAL_PATH_DELIM;
954 		cp = sl;
955 	}
956 	return (0);
957 }	/* MkDirs */
958 
959 
960 
961 
962 int
963 FilenameExtensionIndicatesASCII(const char *const pathName, const char *const extnList)
964 {
965 	const char *extn;
966 	char *cp;
967 	int c;
968 	char extnPattern[16];
969 
970 	extn = pathName + strlen(pathName) - 1;
971 	forever {
972 		if (extn <= pathName)
973 			return (0);	/* End of pathname, no extension. */
974 		c = (int) *--extn;
975 		if (IsLocalPathDelim(c))
976 			return (0);	/* End of filename, no extension. */
977 		if (c == '.') {
978 			extn += 1;
979 			break;
980 		}
981 	}
982 	if (strlen(extn) > (sizeof(extnPattern) - 2 - 1 - 1)) {
983 		return (0);
984 	}
985 #ifdef HAVE_SNPRINTF
986 	snprintf(extnPattern, sizeof(extnPattern),
987 #else
988 	sprintf(extnPattern,
989 #endif
990 		"|.%s|",
991 		extn
992 	);
993 
994 	cp = extnPattern;
995 	forever {
996 		c = *cp;
997 		if (c == '\0')
998 			break;
999 		if (isupper(c)) {
1000 			c = tolower(c);
1001 			*cp++ = (char) c;
1002 		} else {
1003 			cp++;
1004 		}
1005 	}
1006 
1007 	/* Extension list is specially formatted, like this:
1008 	 *
1009 	 * 	|ext1|ext2|ext3|...|extN|
1010 	 *
1011 	 * I.e, each filename extension is delimited with
1012 	 * a pipe, and we always begin and end the string
1013 	 * with a pipe.
1014 	 */
1015 	if (strstr(extnList, extnPattern) != NULL) {
1016 		return (1);
1017 	}
1018 	return (0);
1019 }	/* FilenameExtensionIndicatesASCII */
1020 
1021 
1022 
1023 
1024 
1025 #ifdef HAVE_SIGACTION
1026 void (*NcSignal(int signum, void (*handler)(int)))(int)
1027 {
1028 	struct sigaction sa, osa;
1029 
1030 	(void) sigemptyset(&sa.sa_mask);
1031 	sa.sa_flags = 0;
1032 	sa.sa_handler = handler;
1033 	if (signum == SIGALRM) {
1034 #ifdef SA_INTERRUPT
1035 		sa.sa_flags |= SA_INTERRUPT;
1036 #endif
1037 	} else {
1038 #ifdef SA_RESTART
1039 		sa.sa_flags |= SA_RESTART;
1040 #endif
1041 	}
1042 	if (sigaction(signum, &sa, &osa) < 0)
1043 		return ((FTPSigProc) SIG_ERR);
1044 	return (osa.sa_handler);
1045 }
1046 #endif	/* HAVE_SIGACTION */
1047 
1048 /* eof */
1049