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