|
|
1.1.1.8 ! root 1: /* fileio.c - I/O routines for PGP. ! 2: PGP: Pretty Good(tm) Privacy - public key cryptography for the masses. ! 3: ! 4: (c) Copyright 1990-1996 by Philip Zimmermann. All rights reserved. ! 5: The author assumes no liability for damages resulting from the use ! 6: of this software, even if the damage results from defects in this ! 7: software. No warranty is expressed or implied. ! 8: ! 9: Note that while most PGP source modules bear Philip Zimmermann's ! 10: copyright notice, many of them have been revised or entirely written ! 11: by contributors who frequently failed to put their names in their ! 12: code. Code that has been incorporated into PGP from other authors ! 13: was either originally published in the public domain or is used with ! 14: permission from the various authors. ! 15: ! 16: PGP is available for free to the public under certain restrictions. ! 17: See the PGP User's Guide (included in the release package) for ! 18: important information about licensing, patent restrictions on ! 19: certain algorithms, trademarks, copyrights, and export controls. ! 20: ! 21: Modified 16 Apr 92 - HAJK ! 22: Mods for support of VAX/VMS file system ! 23: ! 24: Modified 17 Nov 92 - HAJK ! 25: Change to temp file stuff for VMS. ! 26: */ ! 27: ! 28: #include <ctype.h> ! 29: #include <stdio.h> ! 30: #include <stdlib.h> ! 31: #include <string.h> ! 32: #include <errno.h> ! 33: #ifdef UNIX ! 34: #include <sys/types.h> ! 35: #include <sys/stat.h> ! 36: #include <fcntl.h> ! 37: #ifdef _BSD ! 38: #include <sys/param.h> ! 39: #endif ! 40: extern int errno; ! 41: #endif /* UNIX */ ! 42: #ifdef VMS ! 43: #include <file.h> ! 44: #include <assert.h> ! 45: #endif ! 46: #include "random.h" ! 47: #include "mpilib.h" ! 48: #include "mpiio.h" ! 49: #include "fileio.h" ! 50: #include "language.h" ! 51: #include "pgp.h" ! 52: #include "exitpgp.h" ! 53: #include "charset.h" ! 54: #include "system.h" ! 55: #if defined(MSDOS) || defined(OS2) || defined (WIN32) ! 56: #include <io.h> ! 57: #include <fcntl.h> ! 58: #endif ! 59: #ifdef MACTC5 ! 60: #include "crypto.h" /* for get_header_info_from_file() */ ! 61: #include "AEStuff.h" ! 62: #include "AppGlobals.h" ! 63: #include "MacPGP.h" ! 64: #include "Macutil2.h" ! 65: #include "Macutil3.h" ! 66: #define MULTIPLE_DOTS ! 67: extern Boolean AEProcessing; ! 68: pascal Boolean idleProc(EventRecord * eventIn, long *sleep, RgnHandle * mouseRgn); ! 69: #endif ! 70: ! 71: char *ck_dup_output(char *, boolean, boolean); ! 72: ! 73: #ifndef F_OK ! 74: #define F_OK 0 ! 75: #define X_OK 1 ! 76: #define W_OK 2 ! 77: #define R_OK 4 ! 78: #endif /* !F_OK */ ! 79: ! 80: /* ! 81: * DIRSEPS is a string of possible directory-separation characters ! 82: * The first one is the preferred one, which goes in between ! 83: * PGPPATH and the file name if PGPPATH is not terminated with a ! 84: * directory separator. ! 85: */ ! 86: ! 87: #if defined(MSDOS) || defined(__MSDOS__) || defined(OS2) || defined (WIN32) ! 88: static char const DIRSEPS[] = "\\/:"; ! 89: #define BSLASH ! 90: ! 91: #elif defined(ATARI) ! 92: static char const DIRSEPS[] = "\\/:"; ! 93: #define BSLASH ! 94: ! 95: #elif defined(UNIX) ! 96: static char const DIRSEPS[] = "/"; ! 97: #define MULTIPLE_DOTS ! 98: ! 99: #elif defined(AMIGA) ! 100: static char const DIRSEPS[] = "/:"; ! 101: #define MULTIPLE_DOTS ! 102: ! 103: #elif defined(VMS) ! 104: static char const DIRSEPS[] = "]:"; ! 105: ! 106: #elif defined(EBCDIC) ! 107: static char const DIRSEPS[] = "("; /* Any more? */ ! 108: #define MULTIPLE_DOTS ! 109: ! 110: #elif defined(MACTC5) ! 111: #define MULTIPLE_DOTS ! 112: static char const DIRSEPS[] = ":"; ! 113: ! 114: #else ! 115: /* #error is not portable, this has the same effect */ ! 116: #include "Unknown OS" ! 117: #endif ! 118: ! 119: #ifdef __PUREC__ ! 120: #include <ext.h> ! 121: int access(const char *name,int flag) ! 122: { ! 123: struct ffblk dummy; ! 124: return findfirst(name,&dummy,-1); ! 125: } ! 126: #endif ! 127: ! 128: /* 1st character of temporary file extension */ ! 129: #define TMP_EXT '$' /* extensions are '.$##' */ ! 130: ! 131: /* The PGPPATH environment variable */ ! 132: ! 133: static char PGPPATH[] = "PGPPATH"; ! 134: ! 135: /* Disk buffers, used here and in crypto.c */ ! 136: byte textbuf[DISKBUFSIZE]; ! 137: static unsigned textbuf2[2 * DISKBUFSIZE / sizeof(unsigned)]; ! 138: ! 139: boolean file_exists(char *filename) ! 140: /* Returns TRUE iff file exists. */ ! 141: { ! 142: #ifdef MACTC5 ! 143: FILE *f; ! 144: /* open file f for read, in binary (not text) mode...*/ ! 145: if ((f = fopen(filename,FOPRBIN)) == NULL) ! 146: return(FALSE); ! 147: fclose(f); ! 148: return(TRUE); ! 149: #else ! 150: return access(filename, F_OK) == 0; ! 151: #endif ! 152: } /* file_exists */ ! 153: ! 154: static boolean is_regular_file(char *filename) ! 155: { ! 156: #ifdef S_ISREG ! 157: struct stat st; ! 158: return stat(filename, &st) != -1 && S_ISREG(st.st_mode); ! 159: #else ! 160: return TRUE; ! 161: #endif ! 162: } ! 163: ! 164: ! 165: /* ! 166: * This wipes a file with pseudo-random data. The purpose of this is to ! 167: * make sure no sensitive information is left on the disk. The use ! 168: * of pseudo-random data is to defeat disk compression drivers (such as ! 169: * Stacker and dblspace) so that we are guaranteed that the entire file ! 170: * has been overwritten. ! 171: * ! 172: * Note that the file MUST be open for read/write. ! 173: * ! 174: * It may not work to eliminate everything from non-volatile storage ! 175: * if the OS you're using does its own paging or swapping. Then ! 176: * it's an issue of how the OS's paging device is wiped, and you can ! 177: * only hope that the space will be reused within a few seconds. ! 178: * ! 179: * Also, some file systems (in particular, the Logging File System ! 180: * for Sprite) do not write new data in the same place as old data, ! 181: * defeating this wiping entirely. Fortunately, such systems ! 182: * usually don't need a swap file, and for small temp files, they ! 183: * do write-behind, so if you create and delete a file fast enough, ! 184: * it never gets written to disk at all. ! 185: */ ! 186: ! 187: /* ! 188: * The data is randomly generated with the size of the file as a seed. ! 189: * The data should be random and not leak information. If someone is ! 190: * examining deleted files, presumably they can reconstruct the file size, ! 191: * so that's not a secret. H'm... this wiping algorithm makes it easy to, ! 192: * given a block of data, find the size of the file it came from ! 193: * and the offset of this block within it. That in turn reveals ! 194: * something about the state of the disk's allocation tables when the ! 195: * file was used, possibly making it easier to find other files created ! 196: * at neaby times - such as plaintext files. Is this acceptable? ! 197: */ ! 198: ! 199: /* ! 200: * Theory of operation: We use the additive congruential RNG ! 201: * r[i] = r[i-24] + r[i-55], from Knuth, Vol. 2. This is fast ! 202: * and has a long enough period that there should be no repetitions ! 203: * in even a huge file. It is seeded with r[-55] through r[-1] ! 204: * using another polynomial-based RNG. We seed a linear feedback ! 205: * shift register (CRC generator) with the size of the swap file, ! 206: * and clock in 0 bits. Each 32 bits, the value of the generator is ! 207: * taken as the next integer. This is just to ensure a reasonably ! 208: * even mix of 1's and 0's in the initialization vector. ! 209: */ ! 210: ! 211: /* ! 212: * This is the CRC-32 polynomial, which should be okay for random ! 213: * number generation. ! 214: * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1 ! 215: * = 1 0000 0100 1100 0001 0001 1101 1011 0111 ! 216: * = 0x04c11db7 ! 217: */ ! 218: #define POLY 0x04c11db7 ! 219: ! 220: static void wipeout(FILE * f) ! 221: { ! 222: unsigned *p1, *p2, *p3; ! 223: unsigned long len; ! 224: unsigned long t; ! 225: int i; ! 226: ! 227: /* Get the file size */ ! 228: fseek(f, 0L, SEEK_END); ! 229: len = ftell(f); ! 230: #ifdef MACTC5 ! 231: len = len + 4096 - (len % 4096); ! 232: #endif ! 233: rewind(f); ! 234: ! 235: /* Seed of first RNG. Inverted to get more 1 bits */ ! 236: t = ~len; ! 237: ! 238: /* Initialize first 55 words of buf with pseudo-random stuff */ ! 239: p1 = (unsigned *) textbuf2 + 55; ! 240: do { ! 241: for (i = 0; i < 32; i++) ! 242: t = (t & 0x80000000) ? t << 1 ^ POLY : t << 1; ! 243: *--p1 = (unsigned) t; ! 244: } while (p1 > (unsigned *) textbuf2); ! 245: ! 246: while (len) { ! 247: /* Fill buffer with pseudo-random integers */ ! 248: ! 249: p3 = (unsigned *) textbuf2 + 55; ! 250: p2 = (unsigned *) textbuf2 + 24; ! 251: p1 = (unsigned *) textbuf2 + sizeof(textbuf2) / sizeof(*p1); ! 252: do { ! 253: *--p1 = *--p2 + *--p3; ! 254: } while (p2 > (unsigned *) textbuf2); ! 255: ! 256: p2 = (unsigned *) textbuf2 + sizeof(textbuf2) / sizeof(*p1); ! 257: do { ! 258: *--p1 = *--p2 + *--p3; ! 259: } while (p3 > (unsigned *) textbuf2); ! 260: ! 261: p3 = (unsigned *) textbuf2 + sizeof(textbuf2) / sizeof(*p3); ! 262: do { ! 263: *--p1 = *--p2 + *--p3; ! 264: } while (p1 > (unsigned *) textbuf2); ! 265: ! 266: /* Write it out - yes, we're ignoring errors */ ! 267: if (len > sizeof(textbuf2)) { ! 268: fwrite((char const *) textbuf2, sizeof(textbuf2), 1, f); ! 269: len -= sizeof(textbuf2); ! 270: #ifdef MACTC5 ! 271: mac_poll_for_break(); ! 272: #endif ! 273: } else { ! 274: fwrite((char const *) textbuf2, len, 1, f); ! 275: len = 0; ! 276: } ! 277: } ! 278: } ! 279: ! 280: ! 281: /* ! 282: * Completely overwrite and erase file, so that no sensitive ! 283: * information is left on the disk. ! 284: */ ! 285: int wipefile(char *filename) ! 286: { ! 287: FILE *f; ! 288: /* open file f for read/write, in binary (not text) mode... */ ! 289: if ((f = fopen(filename, FOPRWBIN)) == NULL) ! 290: return -1; /* error - file can't be opened */ ! 291: wipeout(f); ! 292: fclose(f); ! 293: return 0; /* normal return */ ! 294: } /* wipefile */ ! 295: ! 296: /* ! 297: * Returns the part of a filename after all directory specifiers. ! 298: */ ! 299: char *file_tail(char *filename) ! 300: { ! 301: char *p; ! 302: char const *s = DIRSEPS; ! 303: ! 304: while (*s) { ! 305: p = strrchr(filename, *s); ! 306: if (p) ! 307: filename = p + 1; ! 308: s++; ! 309: } ! 310: ! 311: return filename; ! 312: } ! 313: ! 314: ! 315: /* return TRUE if extension matches the end of filename */ ! 316: boolean has_extension(char *filename, char *extension) ! 317: { ! 318: int lf = strlen(filename); ! 319: int lx = strlen(extension); ! 320: ! 321: if (lf <= lx) ! 322: return FALSE; ! 323: return !strcmp(filename + lf - lx, extension); ! 324: } ! 325: ! 326: /* return TRUE if path is a filename created by tempfile() */ ! 327: /* Filename matches "*.$[0-9][0-9]" */ ! 328: boolean is_tempfile(char *path) ! 329: { ! 330: char *p = strrchr(path, '.'); ! 331: ! 332: return p != NULL && p[1] == TMP_EXT && ! 333: isdigit(p[2]) && isdigit(p[3]) && p[4] == '\0'; ! 334: } ! 335: ! 336: /* ! 337: * Returns TRUE if user left off file extension, allowing default. ! 338: * Note that the name is misleading if multiple dots are allowed. ! 339: * not_pgp_extension or something would be better. ! 340: */ ! 341: boolean no_extension(char *filename) ! 342: { ! 343: #ifdef MULTIPLE_DOTS /* filename can have more than one dot */ ! 344: if (has_extension(filename, ASC_EXTENSION) || ! 345: has_extension(filename, PGP_EXTENSION) || ! 346: has_extension(filename, SIG_EXTENSION) || ! 347: #ifdef MACTC5 ! 348: has_extension(filename,".tmp") || ! 349: #endif ! 350: is_tempfile(filename)) ! 351: return FALSE; ! 352: else ! 353: return TRUE; ! 354: #else ! 355: filename = file_tail(filename); ! 356: ! 357: return strrchr(filename, '.') == NULL; ! 358: #endif ! 359: } /* no_extension */ ! 360: ! 361: ! 362: /* deletes trailing ".xxx" file extension after the period. */ ! 363: void drop_extension(char *filename) ! 364: { ! 365: if (!no_extension(filename)) ! 366: *strrchr(filename, '.') = '\0'; ! 367: } /* drop_extension */ ! 368: ! 369: ! 370: /* append filename extension if there isn't one already. */ ! 371: void default_extension(char *filename, char *extension) ! 372: { ! 373: if (no_extension(filename)) ! 374: strcat(filename, extension); ! 375: } /* default_extension */ ! 376: ! 377: #ifndef MAX_NAMELEN ! 378: #if defined(AMIGA) || defined(NeXT) || (defined(BSD) && BSD > 41) || (defined(sun) && defined(i386)) ! 379: #define MAX_NAMELEN 255 ! 380: #else ! 381: #ifdef MACTC5 ! 382: #define MAX_NAMELEN 31 ! 383: #else ! 384: #include <limits.h> ! 385: #endif ! 386: #endif ! 387: #endif ! 388: ! 389: /* truncate the filename so that an extension can be tacked on. */ ! 390: static void truncate_name(char *path, int ext_len) ! 391: { ! 392: #ifdef UNIX /* for other systems this is a no-op */ ! 393: char *p; ! 394: #ifdef MAX_NAMELEN /* overrides the use of pathconf() */ ! 395: int namemax = MAX_NAMELEN; ! 396: #else ! 397: int namemax; ! 398: #ifdef _PC_NAME_MAX ! 399: char dir[MAX_PATH]; ! 400: ! 401: strcpy(dir, path); ! 402: if ((p = strrchr(dir, '/')) == NULL) { ! 403: strcpy(dir, "."); ! 404: } else { ! 405: if (p == dir) ! 406: ++p; ! 407: *p = '\0'; ! 408: } ! 409: if ((namemax = pathconf(dir, _PC_NAME_MAX)) <= ext_len) ! 410: return; ! 411: #else ! 412: #ifdef NAME_MAX ! 413: namemax = NAME_MAX; ! 414: #else ! 415: namemax = 14; ! 416: #endif /* NAME_MAX */ ! 417: #endif /* _PC_NAME_MAX */ ! 418: #endif /* MAX_NAMELEN */ ! 419: ! 420: if ((p = strrchr(path, '/')) == NULL) ! 421: p = path; ! 422: else ! 423: ++p; ! 424: if (strlen(p) > namemax - ext_len) { ! 425: if (verbose) ! 426: fprintf(pgpout, "Truncating filename '%s' ", path); ! 427: p[namemax - ext_len] = '\0'; ! 428: if (verbose) ! 429: fprintf(pgpout, "to '%s'\n", path); ! 430: } ! 431: #else ! 432: #ifdef MACTC5 ! 433: char *p; ! 434: p = file_tail(path); ! 435: if (verbose) ! 436: fprintf(pgpout, LANG("Truncating filename '%s' "), path); ! 437: if (strlen(p) + ext_len > MAX_NAMELEN) p[MAX_NAMELEN - ext_len] = '\0'; ! 438: #endif /* MACTC5 */ ! 439: #endif /* UNIX */ ! 440: } ! 441: ! 442: /* change the filename extension. */ ! 443: void force_extension(char *filename, char *extension) ! 444: { ! 445: drop_extension(filename); /* out with the old */ ! 446: truncate_name(filename, strlen(extension)); ! 447: strcat(filename, extension); /* in with the new */ ! 448: } /* force_extension */ ! 449: ! 450: ! 451: /* ! 452: * Get yes/no answer from user, returns TRUE for yes, FALSE for no. ! 453: * First the translations are checked, if they don't match 'y' and 'n' ! 454: * are tried. ! 455: */ ! 456: #ifdef MACTC5 ! 457: ! 458: boolean getyesno(char default_answer) ! 459: { ! 460: extern FILE *logfile; ! 461: short alertid,i,large,err; ! 462: char dfault[8], ndfault[8]; ! 463: ProcessSerialNumber psn; ! 464: if (batchmode) ! 465: return(default_answer == 'y' ? TRUE : FALSE); ! 466: if (strlen(Yes_No_Message)<72) large=0; ! 467: else large=100; ! 468: strcpy(dfault,default_answer == 'y' ? LANG("y") : LANG("n")); ! 469: strcpy(ndfault,default_answer == 'n' ? LANG("y") : LANG("n")); ! 470: for(i=0;i<strlen(Yes_No_Message);i++) ! 471: if (Yes_No_Message[i]<' ' && Yes_No_Message[i]>=0) Yes_No_Message[i]=' '; /* It's a signed char! */ ! 472: InitCursor(); ! 473: alertid=(default_answer == 'n' ? 211+large : 212+large); ! 474: c2pstr(Yes_No_Message); ! 475: ParamText((uchar *)Yes_No_Message,(uchar *)"", \ ! 476: (uchar *)"",(uchar *)""); ! 477: if (AEProcessing) { ! 478: if (gHasProcessManager) ! 479: GetFrontProcess(&psn); ! 480: if(MyInteractWithUser()) ! 481: return default_answer; ! 482: if (gHasProcessManager) ! 483: SetFrontProcess(&psn); ! 484: } ! 485: if (CautionAlert(alertid,nil)==1){ ! 486: p2cstr((uchar *)Yes_No_Message); ! 487: fputs(strcat(Yes_No_Message,dfault),stderr); ! 488: fputc('\n',stderr); ! 489: fflush(stderr); ! 490: return(default_answer == 'y' ? TRUE : FALSE); ! 491: } ! 492: p2cstr((uchar *)Yes_No_Message); ! 493: fputs(strcat(Yes_No_Message,ndfault),stderr); ! 494: fputc('\n',stderr); ! 495: fflush(stderr); ! 496: return(default_answer == 'n' ? TRUE : FALSE); ! 497: } ! 498: #else ! 499: ! 500: boolean getyesno(char default_answer) ! 501: { ! 502: char buf[8]; ! 503: static char yes[8], no[8]; ! 504: ! 505: if (yes[0] == '\0') { ! 506: strncpy(yes, LANG("y"), 7); ! 507: strncpy(no, LANG("n"), 7); ! 508: } ! 509: if (!batchmode) { /* return default answer in batchmode */ ! 510: getstring(buf, 6, TRUE); /* echo keyboard input */ ! 511: strlwr(buf); ! 512: if (!strncmp(buf, no, strlen(no))) ! 513: return FALSE; ! 514: if (!strncmp(buf, yes, strlen(yes))) ! 515: return TRUE; ! 516: if (buf[0] == 'n') ! 517: return FALSE; ! 518: if (buf[0] == 'y') ! 519: return TRUE; ! 520: } ! 521: return default_answer == 'y' ? TRUE : FALSE; ! 522: } /* getyesno */ ! 523: #endif ! 524: ! 525: /* if user consents to it, change the filename extension. */ ! 526: char *maybe_force_extension(char *filename, char *extension) ! 527: { ! 528: static char newname[MAX_PATH]; ! 529: if (!has_extension(filename, extension)) { ! 530: strcpy(newname, filename); ! 531: force_extension(newname, extension); ! 532: if (!file_exists(newname)) { ! 533: fprintf(pgpout, LANG("\nShould '%s' be renamed to '%s' (Y/n)? "), ! 534: filename, newname); ! 535: if (getyesno('y')) ! 536: return newname; ! 537: } ! 538: } ! 539: return NULL; ! 540: } /* maybe_force_extension */ ! 541: ! 542: /* ! 543: * Add a trailing directory separator to a name, if absent. ! 544: */ ! 545: static void addslash(char *name) ! 546: { ! 547: int i = strlen(name); ! 548: ! 549: if (i != 0 && !strchr(DIRSEPS, name[i - 1])) { ! 550: name[i] = DIRSEPS[0]; ! 551: name[i + 1] = '\0'; ! 552: } ! 553: } ! 554: ! 555: /* ! 556: * Builds a filename with a complete path specifier from the environmental ! 557: * variable PGPPATH. ! 558: */ ! 559: char *buildfilename(char *result, char *fname) ! 560: { ! 561: #ifdef MACTC5 ! 562: char const *s; ! 563: #else ! 564: char const *s = getenv(PGPPATH); ! 565: #endif ! 566: result[0] = '\0'; ! 567: #ifdef MACTC5 ! 568: return(strcpy(result,fname)); ! 569: #endif ! 570: ! 571: if (s && strlen(s) <= 50) { ! 572: strcpy(result, s); ! 573: } ! 574: #ifdef UNIX ! 575: /* On Unix, default to $HOME/.pgp, otherwise, current directory. */ ! 576: else { ! 577: s = getenv("HOME"); ! 578: if (s && strlen(s) <= 50) { ! 579: strcpy(result, s); ! 580: addslash(result); ! 581: strcat(result, ".pgp"); ! 582: } ! 583: } ! 584: #endif /* UNIX */ ! 585: ! 586: addslash(result); ! 587: strcat(result, fname); ! 588: return result; ! 589: } /* buildfilename */ ! 590: ! 591: char *buildsysfilename(char *result, char *fname) ! 592: { ! 593: buildfilename(result, fname); ! 594: #ifdef PGP_SYSTEM_DIR ! 595: if (file_exists(result)) ! 596: return result; ! 597: strcpy(result, PGP_SYSTEM_DIR); ! 598: strcat(result, fname); ! 599: if (file_exists(result)) ! 600: return result; ! 601: buildfilename(result, fname); /* Put name back for error */ ! 602: #endif ! 603: return result; ! 604: } ! 605: ! 606: ! 607: /* Convert filename to canonical form, with slashes as separators */ ! 608: void file_to_canon(char *filename) ! 609: { ! 610: #ifdef EBCDIC ! 611: CONVERT_TO_CANONICAL_CHARSET(filename); ! 612: #endif ! 613: #ifdef BSLASH ! 614: while (*filename) { ! 615: if (*filename == '\\') ! 616: *filename = '/'; ! 617: ++filename; ! 618: } ! 619: #else /* 203a */ ! 620: #ifdef MACTC5 ! 621: while (*filename) { ! 622: if (*filename == ':') ! 623: *filename = '/'; ! 624: ++filename; ! 625: } ! 626: #endif ! 627: #endif ! 628: } ! 629: ! 630: #ifdef EBCDIC ! 631: /* Convert filename from canonical form */ ! 632: void file_from_canon(char *filename) ! 633: { ! 634: strcpy( filename, LOCAL_CHARSET(filename) ); ! 635: } ! 636: #endif /* EBCDIC */ ! 637: ! 638: ! 639: int write_error(FILE * f) ! 640: { ! 641: fflush(f); ! 642: if (ferror(f)) { ! 643: #ifdef ENOSPC ! 644: if (errno == ENOSPC) ! 645: fprintf(pgpout, LANG("\nDisk full.\n")); ! 646: else ! 647: #endif ! 648: fprintf(pgpout, LANG("\nFile write error.\n")); ! 649: return -1; ! 650: } ! 651: return 0; ! 652: } ! 653: ! 654: /* copy file f to file g, for longcount bytes */ ! 655: int copyfile(FILE * f, FILE * g, word32 longcount) ! 656: { ! 657: int count, status = 0; ! 658: do { /* read and write the whole file... */ ! 659: if (longcount < (word32) DISKBUFSIZE) ! 660: count = (int) longcount; ! 661: else ! 662: count = DISKBUFSIZE; ! 663: count = fread(textbuf, 1, count, f); ! 664: if (count > 0) { ! 665: if (CONVERSION != NO_CONV) { ! 666: int i; ! 667: for (i = 0; i < count; i++) ! 668: textbuf[i] = (CONVERSION == EXT_CONV) ? ! 669: EXT_C(textbuf[i]) : ! 670: INT_C(textbuf[i]); ! 671: } ! 672: if (fwrite(textbuf, 1, count, g) != count) { ! 673: /* Problem: return error value */ ! 674: status = -1; ! 675: break; ! 676: } ! 677: longcount -= count; ! 678: #ifdef MACTC5 ! 679: mac_poll_for_break(); ! 680: #endif ! 681: } ! 682: /* if text block was short, exit loop */ ! 683: } while (count == DISKBUFSIZE); ! 684: burn(textbuf); /* burn sensitive data on stack */ ! 685: return status; ! 686: } /* copyfile */ ! 687: ! 688: /* ! 689: * Like copyfile, but takes a position for file f. Returns with ! 690: * f and g pointing just past the copied data. ! 691: */ ! 692: int copyfilepos(FILE * f, FILE * g, word32 longcount, word32 fpos) ! 693: { ! 694: fseek(f, fpos, SEEK_SET); ! 695: return copyfile(f, g, longcount); ! 696: } ! 697: ! 698: ! 699: /* copy file f to file g, for longcount bytes. Convert to ! 700: * canonical form as we go. f is open in text mode. Canonical ! 701: * form uses crlf's as line separators. ! 702: */ ! 703: int copyfile_to_canon(FILE * f, FILE * g, word32 longcount) ! 704: { ! 705: int count, status = 0; ! 706: byte c, *tb1, *tb2; ! 707: int i, nbytes; ! 708: int nspaces = 0; ! 709: #ifdef MACTC5 ! 710: Boolean warning = true; /* MACTC5 */ ! 711: #endif ! 712: do { /* read and write the whole file... */ ! 713: if (longcount < (word32) DISKBUFSIZE) ! 714: count = (int) longcount; ! 715: else ! 716: count = DISKBUFSIZE; ! 717: count = fread(textbuf, 1, count, f); ! 718: if (count > 0) { ! 719: /* Convert by adding CR before LF */ ! 720: tb1 = textbuf; ! 721: tb2 = (byte *) textbuf2; ! 722: for (i = 0; i < count; ++i) { ! 723: switch (CONVERSION) { ! 724: case EXT_CONV: ! 725: c = EXT_C(*tb1++); ! 726: break; ! 727: case INT_CONV: ! 728: c = INT_C(*tb1++); ! 729: break; ! 730: default: ! 731: c = *tb1++; ! 732: } ! 733: #ifdef MACTC5 ! 734: if ( (((uchar) c) < ' ') && (c != '\n') && (c != '\t') && warning) { ! 735: warning = false; ! 736: fprintf(stdout, "\aWarning text file contains control characters!\n"); ! 737: } ! 738: #endif ! 739: if (strip_spaces) { ! 740: if (c == ' ') { ! 741: /* Don't output spaces yet */ ! 742: nspaces += 1; ! 743: } else { ! 744: if (c == '\n') { ! 745: *tb2++ = '\r'; ! 746: nspaces = 0; /* Delete trailing spaces */ ! 747: } ! 748: if (nspaces) { ! 749: /* Put out spaces now */ ! 750: do ! 751: *tb2++ = ' '; ! 752: while (--nspaces); ! 753: } ! 754: *tb2++ = c; ! 755: } ! 756: } else { ! 757: if (c == '\n') ! 758: *tb2++ = '\r'; ! 759: *tb2++ = c; ! 760: } ! 761: } ! 762: nbytes = tb2 - (byte *) textbuf2; ! 763: if (fwrite(textbuf2, 1, nbytes, g) != nbytes) { ! 764: /* Problem: return error value */ ! 765: status = -1; ! 766: break; ! 767: } ! 768: longcount -= count; ! 769: } ! 770: /* if text block was short, exit loop */ ! 771: } while (count == DISKBUFSIZE); ! 772: burn(textbuf); /* burn sensitive data on stack */ ! 773: burn(textbuf2); ! 774: return status; ! 775: } /* copyfile_to_canon */ ! 776: ! 777: ! 778: /* copy file f to file g, for longcount bytes. Convert from ! 779: * canonical to local form as we go. g is open in text mode. Canonical ! 780: * form uses crlf's as line separators. ! 781: */ ! 782: int copyfile_from_canon(FILE * f, FILE * g, word32 longcount) ! 783: { ! 784: int count, status = 0; ! 785: byte c, *tb1, *tb2; ! 786: int i, nbytes; ! 787: do { /* read and write the whole file... */ ! 788: if (longcount < (word32) DISKBUFSIZE) ! 789: count = (int) longcount; ! 790: else ! 791: count = DISKBUFSIZE; ! 792: count = fread(textbuf, 1, count, f); ! 793: if (count > 0) { ! 794: /* Convert by removing CR's */ ! 795: tb1 = textbuf; ! 796: tb2 = (byte *) textbuf2; ! 797: for (i = 0; i < count; ++i) { ! 798: switch (CONVERSION) { ! 799: case EXT_CONV: ! 800: c = EXT_C(*tb1++); ! 801: break; ! 802: case INT_CONV: ! 803: c = INT_C(*tb1++); ! 804: break; ! 805: default: ! 806: c = *tb1++; ! 807: } ! 808: if (c != '\r') ! 809: *tb2++ = c; ! 810: } ! 811: nbytes = tb2 - (byte *) textbuf2; ! 812: if (fwrite(textbuf2, 1, nbytes, g) != nbytes) { ! 813: /* Problem: return error value */ ! 814: status = -1; ! 815: break; ! 816: } ! 817: longcount -= count; ! 818: } ! 819: /* if text block was short, exit loop */ ! 820: } while (count == DISKBUFSIZE); ! 821: burn(textbuf); /* burn sensitive data on stack */ ! 822: burn(textbuf2); ! 823: return status; ! 824: } /* copyfile_from_canon */ ! 825: ! 826: /* Copy srcFile to destFile */ ! 827: int copyfiles_by_name(char *srcFile, char *destFile) ! 828: { ! 829: FILE *f, *g; ! 830: int status = 0; ! 831: long fileLength; ! 832: ! 833: f = fopen(srcFile, FOPRBIN); ! 834: if (f == NULL) ! 835: return -1; ! 836: g = fopen(destFile, FOPWBIN); ! 837: if (g == NULL) { ! 838: fclose(f); ! 839: return -1; ! 840: } ! 841: /* Get file length and copy it */ ! 842: fseek(f, 0L, SEEK_END); ! 843: fileLength = ftell(f); ! 844: rewind(f); ! 845: status = copyfile(f, g, fileLength); ! 846: fclose(f); ! 847: if (write_error(g)) ! 848: status = -1; ! 849: fclose(g); ! 850: return status; ! 851: } /* copyfiles_by_name */ ! 852: ! 853: /* Copy srcFile to destFile, converting to canonical text form */ ! 854: int make_canonical(char *srcFile, char *destFile) ! 855: { ! 856: FILE *f, *g; ! 857: int status = 0; ! 858: long fileLength; ! 859: ! 860: if (((f = fopen(srcFile, FOPRTXT)) == NULL) || ! 861: ((g = fopen(destFile, FOPWBIN)) == NULL)) ! 862: /* Can't open files */ ! 863: return -1; ! 864: ! 865: /* Get file length and copy it */ ! 866: fseek(f, 0L, SEEK_END); ! 867: fileLength = ftell(f); ! 868: rewind(f); ! 869: CONVERSION = INT_CONV; ! 870: status = copyfile_to_canon(f, g, fileLength); ! 871: CONVERSION = NO_CONV; ! 872: fclose(f); ! 873: if (write_error(g)) ! 874: status = -1; ! 875: fclose(g); ! 876: return status; ! 877: } /* make_canonical */ ! 878: ! 879: /* ! 880: * Like rename() but will try to copy the file if the rename fails. ! 881: * This is because under OS's with multiple physical volumes if the ! 882: * source and destination are on different volumes the rename will fail ! 883: */ ! 884: int rename2(char *srcFile, char *destFile) ! 885: { ! 886: FILE *f, *g; ! 887: #ifdef MACTC5 ! 888: int copy=-1; ! 889: #endif ! 890: int status = 0; ! 891: long fileLength; ! 892: ! 893: #ifdef MACTC5 ! 894: copy=MoveRename(srcFile,destFile); ! 895: if (copy) ! 896: #else ! 897: #if defined(VMS) || defined(C370) ! 898: if (rename(srcFile, destFile) != 0) ! 899: #else ! 900: if (rename(srcFile, destFile) == -1) ! 901: #endif ! 902: #endif ! 903: { ! 904: /* Rename failed, try a copy */ ! 905: if (((f = fopen(srcFile, FOPRBIN)) == NULL) || ! 906: ((g = fopen(destFile, FOPWBIN)) == NULL)) ! 907: /* Can't open files */ ! 908: return -1; ! 909: ! 910: #ifdef MACTC5 ! 911: { ! 912: FInfo finderInfo; ! 913: c2pstr(srcFile); ! 914: c2pstr(destFile); ! 915: if(GetFInfo((uchar *)srcFile,0,&finderInfo)==0) ! 916: SetFInfo((uchar *)destFile,0,&finderInfo); ! 917: p2cstr((uchar *)srcFile); ! 918: p2cstr((uchar *)destFile); ! 919: } ! 920: #endif ! 921: ! 922: /* Get file length and copy it */ ! 923: fseek(f, 0L, SEEK_END); ! 924: fileLength = ftell(f); ! 925: rewind(f); ! 926: status = copyfile(f, g, fileLength); ! 927: if (write_error(g)) ! 928: status = -1; ! 929: ! 930: /* Zap source file if the copy went OK, otherwise zap the (possibly ! 931: incomplete) destination file */ ! 932: if (status >= 0) { ! 933: wipeout(f); /* Zap source file */ ! 934: fclose(f); ! 935: remove(srcFile); ! 936: fclose(g); ! 937: } else { ! 938: if (is_regular_file(destFile)) { ! 939: wipeout(g); /* Zap destination file */ ! 940: fclose(g); ! 941: remove(destFile); ! 942: } else { ! 943: fclose(g); ! 944: } ! 945: fclose(f); ! 946: } ! 947: } ! 948: return status; ! 949: } ! 950: ! 951: /* read the data from stdin to the phantom input file */ ! 952: int readPhantomInput(char *filename) ! 953: { ! 954: FILE *outFilePtr; ! 955: byte buffer[512]; ! 956: int bytesRead, status = 0; ! 957: ! 958: if (verbose) ! 959: fprintf(pgpout, "writing stdin to file %s\n", filename); ! 960: if ((outFilePtr = fopen(filename, FOPWBIN)) == NULL) ! 961: return -1; ! 962: ! 963: #if defined(MSDOS) || defined(OS2) || defined (WIN32) ! 964: /* Under DOS must set input stream to binary mode to avoid data mangling */ ! 965: setmode(fileno(stdin), O_BINARY); ! 966: #endif /* MSDOS || OS2 */ ! 967: while ((bytesRead = fread(buffer, 1, 512, stdin)) > 0) ! 968: if (fwrite(buffer, 1, bytesRead, outFilePtr) != bytesRead) { ! 969: status = -1; ! 970: break; ! 971: } ! 972: if (write_error(outFilePtr)) ! 973: status = -1; ! 974: fclose(outFilePtr); ! 975: #if defined(MSDOS) || defined(OS2) || defined (WIN32) ! 976: setmode(fileno(stdin), O_TEXT); /* Reset stream */ ! 977: #endif /* MSDOS || OS2 */ ! 978: return status; ! 979: } ! 980: ! 981: /* write the data from the phantom output file to stdout */ ! 982: int writePhantomOutput(char *filename) ! 983: { ! 984: FILE *outFilePtr; ! 985: byte buffer[512]; ! 986: int bytesRead, status = 0; ! 987: ! 988: if (verbose) ! 989: fprintf(pgpout, "writing file %s to stdout\n", filename); ! 990: /* this can't fail since we just created the file */ ! 991: outFilePtr = fopen(filename, FOPRBIN); ! 992: ! 993: #if defined(MSDOS) || defined(OS2) || defined (WIN32) ! 994: setmode(fileno(stdout), O_BINARY); ! 995: #endif /* MSDOS || OS2 */ ! 996: while ((bytesRead = fread(buffer, 1, 512, outFilePtr)) > 0) ! 997: if (fwrite(buffer, 1, bytesRead, stdout) != bytesRead) { ! 998: status = -1; ! 999: break; ! 1000: } ! 1001: fclose(outFilePtr); ! 1002: fflush(stdout); ! 1003: if (ferror(stdout)) { ! 1004: status = -1; ! 1005: fprintf(pgpout, LANG("\007Write error on stdout.\n")); ! 1006: } ! 1007: #if defined(MSDOS) || defined(OS2) || defined (WIN32) ! 1008: setmode(fileno(stdout), O_TEXT); ! 1009: #endif /* MSDOS || OS2 */ ! 1010: ! 1011: return status; ! 1012: } ! 1013: ! 1014: /* Return the size from the current position of file f to the end */ ! 1015: word32 fsize(FILE * f) ! 1016: { ! 1017: long fpos = ftell(f); ! 1018: long fpos2; ! 1019: ! 1020: fseek(f, 0L, SEEK_END); ! 1021: fpos2 = ftell(f); ! 1022: fseek(f, fpos, SEEK_SET); ! 1023: return (word32) (fpos2 - fpos); ! 1024: } ! 1025: ! 1026: /* Return TRUE if file filename looks like a pure text file */ ! 1027: int is_text_file (char *filename) /* EWS */ ! 1028: { ! 1029: FILE *f = fopen(filename,"r"); /* FOPRBIN gives problem with VMS */ ! 1030: int i, n, lfctr = 0; ! 1031: unsigned char buf[512]; ! 1032: unsigned char *bufptr = buf; ! 1033: unsigned char c; ! 1034: ! 1035: if (!f) ! 1036: return FALSE; /* error opening it, so not a text file */ ! 1037: i = n = fread (buf, 1, sizeof(buf), f); ! 1038: fclose(f); ! 1039: if (n <= 0) ! 1040: return FALSE; /* empty file or error, not a text file */ ! 1041: if (compressSignature(buf) >= 0) ! 1042: return FALSE; ! 1043: while (i--) { ! 1044: c = *bufptr++; ! 1045: if (c == '\n' || c == '\r') ! 1046: lfctr=0; ! 1047: else /* allow BEL BS HT LF VT FF CR EOF control characters */ ! 1048: { ! 1049: #ifdef EBCDIC ! 1050: if (iscntrl(c) && c!=BEL && c!=BS && c!=HT && c!=LF && c!=VT && c!=FF && c!=CR && c!=EOF) ! 1051: #else ! 1052: if (c < '\007' || (c > '\r' && c < ' ' && c != '\032')) ! 1053: #endif ! 1054: return FALSE; /* not a text file */ ! 1055: lfctr++; ! 1056: if (lfctr>132) return FALSE; /* line too long. Not a text file*/ ! 1057: } ! 1058: } ! 1059: return TRUE; ! 1060: } /* is_text_file */ ! 1061: ! 1062: VOID *xmalloc(unsigned size) ! 1063: { ! 1064: VOID *p; ! 1065: if (size == 0) ! 1066: ++size; ! 1067: p = malloc(size); ! 1068: if (p == NULL) { ! 1069: fprintf(stderr, LANG("\n\007Out of memory.\n")); ! 1070: exitPGP(1); ! 1071: } ! 1072: return p; ! 1073: } ! 1074: ! 1075: /*---------------------------------------------------------------------- ! 1076: * temporary file routines ! 1077: */ ! 1078: ! 1079: ! 1080: #define MAXTMPF 8 ! 1081: ! 1082: #define TMP_INUSE 2 ! 1083: ! 1084: static struct { ! 1085: char path[MAX_PATH]; ! 1086: int flags; ! 1087: int num; ! 1088: } tmpf[MAXTMPF]; ! 1089: ! 1090: static char tmpdir[256]; /* temporary file directory */ ! 1091: static char outdir[256]; /* output directory */ ! 1092: static char tmpbasename[64] = "pgptemp"; /* basename for ! 1093: temporary files */ ! 1094: ! 1095: ! 1096: /* ! 1097: * set directory for temporary files. path will be stored in ! 1098: * tmpdir[] with an appropriate trailing path separator. ! 1099: */ ! 1100: void settmpdir(char *path) ! 1101: { ! 1102: char *p; ! 1103: ! 1104: if (path == NULL || *path == '\0') { ! 1105: tmpdir[0] = '\0'; ! 1106: return; ! 1107: } ! 1108: strcpy(tmpdir, path); ! 1109: p = tmpdir + strlen(tmpdir) - 1; ! 1110: #ifdef MACTC5 ! 1111: if (*p != '/' && *p != '\\' && *p != ']' && *p != ':') ! 1112: { /* append path separator, either / or \ */ ! 1113: if ((p = strchr(tmpdir, '/')) == NULL && ! 1114: (p = strchr(tmpdir, '\\')) == NULL && ! 1115: (p = strchr(tmpdir, ':')) == NULL) ! 1116: p = ":"; /* path did not contain / or \ or :, use : */ ! 1117: strncat(tmpdir, p, 1); ! 1118: #else ! 1119: if (*p != '/' && *p != '\\' && *p != ']' && *p != ':') { ! 1120: /* append path separator, either / or \ */ ! 1121: if ((p = strchr(tmpdir, '/')) == NULL && ! 1122: (p = strchr(tmpdir, '\\')) == NULL) ! 1123: p = "/"; /* path did not contain / or \, use / */ ! 1124: strncat(tmpdir, p, 1); ! 1125: #endif ! 1126: } ! 1127: } ! 1128: ! 1129: /* ! 1130: * set output directory to avoid a file copy when temp file is renamed to ! 1131: * output file. the argument filename must be a valid path for a file, not ! 1132: * a directory. ! 1133: */ ! 1134: void setoutdir(char *filename) ! 1135: { ! 1136: char *p; ! 1137: ! 1138: if (filename == NULL) { ! 1139: strcpy(outdir, tmpdir); ! 1140: return; ! 1141: } ! 1142: strcpy(outdir, filename); ! 1143: p = file_tail(outdir); ! 1144: strcpy(tmpbasename, p); ! 1145: *p = '\0'; ! 1146: drop_extension(tmpbasename); ! 1147: #if !defined(BSD42) && !defined(BSD43) && !defined(sun) ! 1148: /* ! 1149: * we don't depend on pathconf here, if it returns an incorrect value ! 1150: * for NAME_MAX (like Linux 0.97 with minix FS) finding a unique name ! 1151: * for temp files can fail. ! 1152: */ ! 1153: tmpbasename[10] = '\0'; /* 14 char limit */ ! 1154: #endif ! 1155: } ! 1156: ! 1157: /* ! 1158: * return a unique temporary file name ! 1159: */ ! 1160: char *tempfile(int flags) ! 1161: { ! 1162: int i, j; ! 1163: int num; ! 1164: int fd; ! 1165: #ifndef UNIX ! 1166: FILE *fp; ! 1167: #endif ! 1168: ! 1169: for (i = 0; i < MAXTMPF; ++i) ! 1170: if (tmpf[i].flags == 0) ! 1171: break; ! 1172: ! 1173: if (i == MAXTMPF) { ! 1174: /* message only for debugging, no need for LANG */ ! 1175: fprintf(stderr, "\n\007Out of temporary files\n"); ! 1176: return NULL; ! 1177: } ! 1178: again: ! 1179: num = 0; ! 1180: do { ! 1181: for (j = 0; j < MAXTMPF; ++j) ! 1182: if (tmpf[j].flags && tmpf[j].num == num) ! 1183: break; ! 1184: if (j < MAXTMPF) ! 1185: continue; /* sequence number already in use */ ! 1186: sprintf(tmpf[i].path, "%s%s.%c%02d", ! 1187: ((flags & TMP_TMPDIR) && *tmpdir ? tmpdir : outdir), ! 1188: tmpbasename, TMP_EXT, num); ! 1189: if (!file_exists(tmpf[i].path)) ! 1190: break; ! 1191: } ! 1192: while (++num < 100); ! 1193: ! 1194: if (num == 100) { ! 1195: fprintf(pgpout, "\n\007tempfile: cannot find unique name\n"); ! 1196: return NULL; ! 1197: } ! 1198: #if defined(UNIX) || defined(VMS) ! 1199: if ((fd = open(tmpf[i].path, O_EXCL | O_RDWR | O_CREAT, 0600)) != -1) ! 1200: close(fd); ! 1201: #else ! 1202: if ((fp = fopen(tmpf[i].path, "w")) != NULL) ! 1203: fclose(fp); ! 1204: fd = (fp == NULL ? -1 : 0); ! 1205: #endif ! 1206: ! 1207: if (fd == -1) { ! 1208: if (!(flags & TMP_TMPDIR)) { ! 1209: flags |= TMP_TMPDIR; ! 1210: goto again; ! 1211: } ! 1212: #ifdef UNIX ! 1213: else if (tmpdir[0] == '\0') { ! 1214: strcpy(tmpdir, "/tmp/"); ! 1215: goto again; ! 1216: } ! 1217: #endif ! 1218: } ! 1219: if (fd == -1) { ! 1220: fprintf(pgpout, LANG("\n\007Cannot create temporary file '%s'\n"), ! 1221: tmpf[i].path); ! 1222: user_error(); ! 1223: } ! 1224: #if defined(VMS) || defined(C370) ! 1225: remove(tmpf[i].path); ! 1226: #endif ! 1227: ! 1228: tmpf[i].num = num; ! 1229: tmpf[i].flags = flags | TMP_INUSE; ! 1230: if (verbose) ! 1231: fprintf(pgpout, "tempfile: created '%s'\n", tmpf[i].path); ! 1232: return tmpf[i].path; ! 1233: } /* tempfile */ ! 1234: ! 1235: /* ! 1236: * remove temporary file, wipe if necessary. ! 1237: */ ! 1238: void rmtemp(char *name) ! 1239: { ! 1240: int i; ! 1241: ! 1242: for (i = 0; i < MAXTMPF; ++i) ! 1243: if (tmpf[i].flags && strcmp(tmpf[i].path, name) == 0) ! 1244: break; ! 1245: ! 1246: if (i < MAXTMPF) { ! 1247: if (strlen(name) > 3 && name[strlen(name) - 3] == TMP_EXT) { ! 1248: /* only remove file if name hasn't changed */ ! 1249: if (verbose) ! 1250: fprintf(pgpout, "rmtemp: removing '%s'\n", name); ! 1251: if (tmpf[i].flags & TMP_WIPE) ! 1252: wipefile(name); ! 1253: if (!remove(name)) { ! 1254: tmpf[i].flags = 0; ! 1255: } else if (verbose) { ! 1256: fprintf(stderr, "\nrmtemp: Failed to remove %s", name); ! 1257: perror("\nError"); ! 1258: } ! 1259: } else if (verbose) ! 1260: fprintf(pgpout, "rmtemp: not removing '%s'\n", name); ! 1261: } ! 1262: } /* rmtemp */ ! 1263: ! 1264: /* ! 1265: * make temporary file permanent, returns the new name. ! 1266: */ ! 1267: char *savetemp(char *name, char *newname) ! 1268: { ! 1269: int i, overwrite; ! 1270: ! 1271: if (strcmp(name, newname) == 0) ! 1272: return name; ! 1273: ! 1274: for (i = 0; i < MAXTMPF; ++i) ! 1275: if (tmpf[i].flags && strcmp(tmpf[i].path, name) == 0) ! 1276: break; ! 1277: ! 1278: if (i < MAXTMPF) { ! 1279: if (strlen(name) < 4 || name[strlen(name) - 3] != TMP_EXT) { ! 1280: if (verbose) ! 1281: fprintf(pgpout, "savetemp: not renaming '%s' to '%s'\n", ! 1282: name, newname); ! 1283: return name; /* return original file name */ ! 1284: } ! 1285: } ! 1286: ! 1287: newname = ck_dup_output(newname, FALSE, TRUE); ! 1288: if (newname==NULL) ! 1289: return(NULL); ! 1290: ! 1291: if (verbose) ! 1292: fprintf(pgpout, "savetemp: renaming '%s' to '%s'\n", name, newname); ! 1293: if (rename2(name, newname) < 0) { ! 1294: /* errorLvl = UNKNOWN_FILE_ERROR; */ ! 1295: fprintf(pgpout, LANG("Can't create output file '%s'\n"), newname); ! 1296: return NULL; ! 1297: } ! 1298: if (i < MAXTMPF) ! 1299: tmpf[i].flags = 0; ! 1300: return newname; ! 1301: } /* savetemp */ ! 1302: ! 1303: char *ck_dup_output(char *newname, boolean notest, boolean delete_dup) ! 1304: { ! 1305: int overwrite; ! 1306: static char buf[MAX_PATH]; ! 1307: ! 1308: while (file_exists(newname)) { ! 1309: if (batchmode && !force_flag) { ! 1310: fprintf(pgpout,LANG("\n\007Output file '%s' already exists.\n"), ! 1311: newname); ! 1312: return NULL; ! 1313: } ! 1314: if (is_regular_file(newname)) { ! 1315: if (force_flag) { ! 1316: /* remove without asking */ ! 1317: if (delete_dup) remove(newname); ! 1318: break; ! 1319: } ! 1320: fprintf(pgpout, ! 1321: LANG("\n\007Output file '%s' already exists. Overwrite (y/N)? "), ! 1322: newname); ! 1323: overwrite = getyesno('n'); ! 1324: } else { ! 1325: fprintf(pgpout, ! 1326: LANG("\n\007Output file '%s' already exists.\n"),newname); ! 1327: if (force_flag) /* never remove special file */ ! 1328: return NULL; ! 1329: overwrite = FALSE; ! 1330: } ! 1331: ! 1332: if (!overwrite) { ! 1333: fprintf(pgpout, "\n"); ! 1334: fprintf(pgpout, LANG("Enter new file name:")); ! 1335: fprintf(pgpout, " "); ! 1336: #ifdef MACTC5 ! 1337: if (!GetFilePath(LANG("Enter new file name:"), buf, PUTFILE)) ! 1338: return(NULL); ! 1339: strcpy(newname, buf); ! 1340: fprintf(pgpout, "%s\n",buf); ! 1341: #else ! 1342: getstring(buf, MAX_PATH - 1, TRUE); ! 1343: if (buf[0] == '\0') ! 1344: return(NULL); ! 1345: newname = buf; ! 1346: #endif ! 1347: } else if (delete_dup) ! 1348: remove(newname); ! 1349: else ! 1350: break; ! 1351: ! 1352: if (notest) break; ! 1353: } ! 1354: return(newname); ! 1355: } /* ck_dup_output */ ! 1356: ! 1357: /* ! 1358: * like savetemp(), only make backup of destname if it exists ! 1359: */ ! 1360: int savetempbak(char *tmpname, char *destname) ! 1361: { ! 1362: char bakpath[MAX_PATH]; ! 1363: #ifdef MACTC5 ! 1364: byte header[8]; ! 1365: #endif ! 1366: #ifdef UNIX ! 1367: int mode = -1; ! 1368: #endif ! 1369: ! 1370: if (is_tempfile(destname)) { ! 1371: remove(destname); ! 1372: } else { ! 1373: if (file_exists(destname)) { ! 1374: #ifdef UNIX ! 1375: struct stat st; ! 1376: if (stat(destname, &st) != -1) ! 1377: mode = st.st_mode & 07777; ! 1378: #endif ! 1379: strcpy(bakpath, destname); ! 1380: force_extension(bakpath, BAK_EXTENSION); ! 1381: remove(bakpath); ! 1382: #if defined(VMS) || defined(C370) ! 1383: if (rename(destname, bakpath) != 0) ! 1384: #else ! 1385: if (rename(destname, bakpath) == -1) ! 1386: #endif ! 1387: return -1; ! 1388: #ifdef MACTC5 ! 1389: get_header_info_from_file(bakpath, header, 8 ); ! 1390: if (header[0] == CTB_CERT_SECKEY) ! 1391: PGPSetFinfo(bakpath,'SKey','MPGP'); ! 1392: if (header[0] == CTB_CERT_PUBKEY) ! 1393: PGPSetFinfo(bakpath,'PKey','MPGP'); ! 1394: #endif ! 1395: } ! 1396: } ! 1397: if (savetemp(tmpname, destname) == NULL) ! 1398: return -1; ! 1399: #if defined(UNIX) ! 1400: if (mode != -1) ! 1401: chmod(destname, mode); ! 1402: #elif defined(MACTC5) ! 1403: get_header_info_from_file(destname, header, 8 ); ! 1404: if (header[0] == CTB_CERT_SECKEY) ! 1405: PGPSetFinfo(destname,'SKey','MPGP'); ! 1406: if (header[0] == CTB_CERT_PUBKEY) ! 1407: PGPSetFinfo(destname,'PKey','MPGP'); ! 1408: #endif ! 1409: return 0; ! 1410: } ! 1411: ! 1412: /* ! 1413: * remove all temporary files and wipe them if necessary ! 1414: */ ! 1415: void cleanup_tmpf(void) ! 1416: { ! 1417: int i; ! 1418: ! 1419: for (i = 0; i < MAXTMPF; ++i) ! 1420: if (tmpf[i].flags) ! 1421: rmtemp(tmpf[i].path); ! 1422: } /* cleanup_tmpf */ ! 1423: ! 1424: #ifdef MACTC5 ! 1425: void mac_cleanup_tmpf(void) ! 1426: { ! 1427: int i,err; ! 1428: HFileParam pb; ! 1429: char fname[256]; ! 1430: for (i = 0; i < MAXTMPF; ++i) ! 1431: if (tmpf[i].flags) ! 1432: { ! 1433: strcpy(fname,tmpf[i].path); ! 1434: pb.ioCompletion=nil; ! 1435: c2pstr(fname); ! 1436: pb.ioNamePtr=(uchar *)fname; ! 1437: pb.ioVRefNum=0; ! 1438: pb.ioFDirIndex=0; ! 1439: pb.ioFRefNum=0; ! 1440: pb.ioDirID=0; ! 1441: err=PBHGetFInfo((HParmBlkPtr)&pb,false); ! 1442: if (pb.ioFRefNum!=0){ ! 1443: strcpy(fname,tmpf[i].path); ! 1444: pb.ioCompletion=nil; ! 1445: c2pstr(fname); ! 1446: pb.ioNamePtr=(uchar *)fname; ! 1447: pb.ioVRefNum=0; ! 1448: pb.ioDirID=0; ! 1449: err=PBClose((ParmBlkPtr)&pb,false); ! 1450: } ! 1451: rmtemp(tmpf[i].path); ! 1452: } ! 1453: } /* mac_cleanup_tmpf */ ! 1454: #endif ! 1455: ! 1456: /* ! 1457: * Routines to search for the manuals. ! 1458: * ! 1459: * Why all this code? ! 1460: * ! 1461: * Some people may object to PGP insisting on finding the manual somewhere ! 1462: * in the neighborhood to generate a key. They bristle against this ! 1463: * seemingly authoritarian attitude. Some people have even modified PGP ! 1464: * to defeat this feature, and redistributed their hotwired version to ! 1465: * others. That creates problems for me (PRZ). ! 1466: * ! 1467: * Here is the problem. Before I added this feature, there were maimed ! 1468: * versions of the PGP distribution package floating around that lacked ! 1469: * the manual. One of them was uploaded to Compuserve, and was ! 1470: * distributed to countless users who called me on the phone to ask me why ! 1471: * such a complicated program had no manual. It spread out to BBS systems ! 1472: * around the country. And a freeware distributor got hold of the package ! 1473: * from Compuserve and enshrined it on CD-ROM, distributing thousands of ! 1474: * copies without the manual. What a mess. ! 1475: * ! 1476: * Please don't make my life harder by modifying PGP to disable this ! 1477: * feature so that others may redistribute PGP without the manual. If you ! 1478: * run PGP on a palmtop with no memory for the manual, is it too much to ! 1479: * ask that you type one little extra word on the command line to do a key ! 1480: * generation, a command that is seldom used by people who already know ! 1481: * how to use PGP? If you can't stand even this trivial inconvenience, ! 1482: * can you suggest a better method of reducing PGP's distribution without ! 1483: * the manual? ! 1484: */ ! 1485: ! 1486: static unsigned ext_missing(char *prefix) ! 1487: { ! 1488: static char const *const extensions[] = ! 1489: #ifdef VMS ! 1490: { ".doc", ".txt", ".man", ".tex", ".", 0 }; ! 1491: #else ! 1492: { ".doc", ".txt", ".man", ".tex", "", 0 }; ! 1493: #endif ! 1494: char const *const *p; ! 1495: char *end = prefix + strlen(prefix); ! 1496: ! 1497: for (p = extensions; *p; p++) { ! 1498: strcpy(end, *p); ! 1499: #if 0 /* Debugging code */ ! 1500: fprintf(pgpout, "Looking for \"%s\"\n", prefix); ! 1501: #endif ! 1502: if (file_exists(prefix)) ! 1503: return 0; ! 1504: } ! 1505: return 1; ! 1506: } ! 1507: ! 1508: /* ! 1509: * Returns mask of files missing ! 1510: */ ! 1511: static unsigned files_missing(char *prefix) ! 1512: { ! 1513: /* This changed to incorporate the changes in the Documentation subdirectory */ ! 1514: #ifdef MACTC5 ! 1515: static char const *const names[] = ! 1516: {"Volume I", "Volume II", 0}; ! 1517: #else ! 1518: static char const *const names[] = ! 1519: {"pgpdoc1", "pgpdoc2", 0}; ! 1520: #endif ! 1521: char const *const *p; ! 1522: unsigned bit, mask = 3; ! 1523: int len = strlen(prefix); ! 1524: ! 1525: #ifndef MACTC5 ! 1526: /* Cannot do this on the macintosh because file_exists returns false on ! 1527: directories */ ! 1528: #ifndef VMS ! 1529: /* ! 1530: * Optimization: if directory doesn't exist, stop. But access() ! 1531: * (used internally by file_exists()) doesn't work on dirs under VMS. ! 1532: */ ! 1533: if (prefix[0] && !file_exists(prefix)) /* Directory doesn't exist? */ ! 1534: return mask; ! 1535: #endif /* VMS */ ! 1536: #endif /* MACTC5 */ ! 1537: if (len && strchr(DIRSEPS, prefix[len - 1]) == 0) ! 1538: prefix[len++] = DIRSEPS[0]; ! 1539: for (p = names, bit = 1; *p; p++, bit <<= 1) { ! 1540: strcpy(prefix + len, *p); ! 1541: if (!ext_missing(prefix)) ! 1542: mask &= ~bit; ! 1543: } ! 1544: ! 1545: return mask; /* Bitmask of which files exist */ ! 1546: } ! 1547: ! 1548: /* ! 1549: * Search prefix directory and doc subdirectory. ! 1550: */ ! 1551: static unsigned doc_missing(char *prefix) ! 1552: { ! 1553: unsigned mask; ! 1554: int len = strlen(prefix); ! 1555: ! 1556: mask = files_missing(prefix); ! 1557: if (!mask) ! 1558: return 0; ! 1559: #if defined(VMS) ! 1560: if (len && prefix[len - 1] == ']') { ! 1561: strcpy(prefix + len - 1, ".doc]"); ! 1562: } else { ! 1563: assert(!len || prefix[len - 1] == ':'); ! 1564: strcpy(prefix + len, "[doc]"); ! 1565: } ! 1566: #elif defined(MACTC5) ! 1567: /* on the macintosh we must look for the documents in ! 1568: Documentation:PGP User's Guide: folder */ ! 1569: if (len && prefix[len - 1] != DIRSEPS[0]) ! 1570: prefix[len++] = DIRSEPS[0]; ! 1571: strcpy(prefix + len, "Documentation"); ! 1572: len = strlen(prefix); ! 1573: mask &= files_missing(prefix); ! 1574: if (!mask) ! 1575: return 0; ! 1576: if (len && prefix[len - 1] != DIRSEPS[0]) ! 1577: prefix[len++] = DIRSEPS[0]; ! 1578: strcpy(prefix + len, "PGP User's Guide"); ! 1579: mask &= files_missing(prefix); ! 1580: if (!mask) ! 1581: return 0; ! 1582: #else ! 1583: if (len && prefix[len - 1] != DIRSEPS[0]) ! 1584: prefix[len++] = DIRSEPS[0]; ! 1585: strcpy(prefix + len, "doc"); ! 1586: #endif ! 1587: ! 1588: mask &= files_missing(prefix); ! 1589: ! 1590: prefix[len] = '\0'; ! 1591: return mask; ! 1592: } ! 1593: ! 1594: /* ! 1595: * Expands a leading environment variable. Returns 0 on success; ! 1596: * <0 if there is an error. ! 1597: */ ! 1598: static int expand_env(char const *src, char *dest) ! 1599: { ! 1600: char const *var, *suffix; ! 1601: unsigned len; ! 1602: ! 1603: if (*src != '$') { ! 1604: strcpy(dest, src); ! 1605: return 0; ! 1606: } ! 1607: /* Find end of variable */ ! 1608: if (src[1] == '{') { /* ${FOO} form */ ! 1609: var = src + 2; ! 1610: len = strchr(var, '}') - (char*) var; ! 1611: suffix = src + 2 + len + 1; ! 1612: } else { /* $FOO form - allow $ for VMS */ ! 1613: var = src + 1; ! 1614: len = strspn(var, "ABCDEFGHIJKLMNOPQRSTUVWXYZ$_"); ! 1615: suffix = src + 1 + len; ! 1616: } ! 1617: ! 1618: memcpy(dest, var, len); /* Copy name */ ! 1619: dest[len] = '\0'; /* Null-terminate */ ! 1620: ! 1621: var = getenv(dest); ! 1622: if (!var || !*var) ! 1623: return -1; /* No env variable */ ! 1624: ! 1625: /* Copy expanded form to destination */ ! 1626: strcpy(dest, var); ! 1627: ! 1628: /* Add tail */ ! 1629: strcat(dest, suffix); ! 1630: ! 1631: return 0; ! 1632: } ! 1633: ! 1634: /* Don't forget to change 'pgp26' whenever you update rel_version past 2.6 */ ! 1635: char const *const manual_dirs[] = ! 1636: { ! 1637: #if defined(VMS) ! 1638: "$PGPPATH", "", "[pgp]", "[pgp26]", "[pgp263]", ! 1639: PGP_SYSTEM_DIR, "SYS$LOGIN:", "SYS$LOGIN:[pgp]", ! 1640: "SYS$LOGIN:[pgp26]", "SYS$LOGIN:[pgp263]", "[-]", ! 1641: #elif defined(UNIX) ! 1642: "$PGPPATH", "", "pgp", "pgp26", "pgp263", PGP_SYSTEM_DIR, ! 1643: "$HOME/.pgp", "$HOME", "$HOME/pgp", "$HOME/pgp26", "..", ! 1644: #elif defined(AMIGA) ! 1645: "$PGPPATH", "", "pgp", "pgp26", ":pgp", ":pgp26", ":pgp263", ! 1646: ":", "/", ! 1647: #else /* MSDOS or ATARI */ ! 1648: "$PGPPATH", "", "pgp", "pgp26", "\\pgp", "\\pgp26", "\\pgp263", ! 1649: "\\", "..", "c:\\pgp", "c:\\pgp26", ! 1650: #endif ! 1651: 0}; ! 1652: ! 1653: #ifdef MACTC5 ! 1654: extern char appPathName[]; ! 1655: #endif ! 1656: ! 1657: unsigned manuals_missing(void) ! 1658: { ! 1659: char buf[256]; ! 1660: unsigned mask = ~((unsigned)0); ! 1661: char const *const *p; ! 1662: ! 1663: #ifdef MACTC5 ! 1664: strcpy(buf, appPathName); ! 1665: mask &= doc_missing(buf); ! 1666: return mask; ! 1667: #endif /* MACTC5 */ ! 1668: for (p = manual_dirs; *p; p++) { ! 1669: if (expand_env(*p, buf) < 0) ! 1670: continue; /* Ignore */ ! 1671: mask &= doc_missing(buf); ! 1672: if (!mask) ! 1673: break; ! 1674: } ! 1675: ! 1676: return mask; ! 1677: } ! 1678: ! 1679: /* ! 1680: * Why all this code? ! 1681: * ! 1682: * See block of comments above. ! 1683: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.