|
|
1.1.1.6 ! root 1: /* fileio.c - I/O routines for PGP. ! 2: PGP: Pretty Good(tm) Privacy - public key cryptography for the masses. 1.1.1.5 root 3: 1.1.1.6 ! root 4: (c) Copyright 1990-1994 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: */ 1.1.1.5 root 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; 1.1.1.6 ! root 41: #endif /* UNIX */ 1.1.1.5 root 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) 56: #include <io.h> 57: #include <fcntl.h> 58: #endif 59: 60: #ifndef F_OK 61: #define F_OK 0 62: #define X_OK 1 63: #define W_OK 2 64: #define R_OK 4 1.1.1.6 ! root 65: #endif /* !F_OK */ 1.1.1.5 root 66: 67: /* 68: * DIRSEPS is a string of possible directory-separation characters 69: * The first one is the preferred one, which goes in between 70: * PGPPATH and the file name if PGPPATH is not terminated with a 71: * directory separator. 72: */ 73: 1.1.1.6 ! root 74: #if defined(MSDOS) || defined(__MSDOS__) || defined(OS2) 1.1.1.5 root 75: static char const DIRSEPS[] = "\\/:"; 76: #define BSLASH 77: 78: #elif defined(ATARI) 79: static char const DIRSEPS[] = "\\/:"; 80: #define BSLASH 81: 82: #elif defined(UNIX) 83: static char const DIRSEPS[] = "/"; 84: #define MULTIPLE_DOTS 85: 86: #elif defined(AMIGA) 87: static char const DIRSEPS[] = "/:"; 88: #define MULTIPLE_DOTS 89: 90: #elif defined(VMS) 1.1.1.6 ! root 91: static char const DIRSEPS[] = "]:"; /* Any more? */ 1.1.1.5 root 92: 93: #else 1.1.1.6 ! root 94: /* #error is not portable, this has the same effect */ ! 95: #include "Unknown OS" 1.1.1.5 root 96: #endif 97: 98: 99: /* 1st character of temporary file extension */ 100: #define TMP_EXT '$' /* extensions are '.$##' */ 101: 102: /* The PGPPATH environment variable */ 103: 104: static char PGPPATH[] = "PGPPATH"; 105: 106: /* Disk buffers, used here and in crypto.c */ 107: byte textbuf[DISKBUFSIZE]; 1.1.1.6 ! root 108: static unsigned textbuf2[2 * DISKBUFSIZE / sizeof(unsigned)]; 1.1.1.5 root 109: 110: boolean file_exists(char *filename) 1.1.1.6 ! root 111: /* Returns TRUE iff file exists. */ 1.1.1.5 root 112: { 1.1.1.6 ! root 113: return access(filename, F_OK) == 0; ! 114: } /* file_exists */ 1.1.1.5 root 115: 116: static boolean is_regular_file(char *filename) 117: { 118: #ifdef S_ISREG 1.1.1.6 ! root 119: struct stat st; ! 120: return stat(filename, &st) != -1 && S_ISREG(st.st_mode); 1.1.1.5 root 121: #else 1.1.1.6 ! root 122: return TRUE; 1.1.1.5 root 123: #endif 124: } 125: 126: 127: /* 128: * This wipes a file with pseudo-random data. The purpose of this is to 129: * make sure no sensitive information is left on the disk. The use 130: * of pseudo-random data is to defeat disk compression drivers (such as 131: * Stacker and dblspace) so that we are guaranteed that the entire file 132: * has been overwritten. 133: * 134: * Note that the file MUST be open for read/write. 135: * 136: * It may not work to eliminate everything from non-volatile storage 137: * if the OS you're using does its own paging or swapping. Then 138: * it's an issue of how the OS's paging device is wiped, and you can 139: * only hope that the space will be reused within a few seconds. 140: * 141: * Also, some file systems (in particular, the Logging File System 142: * for Sprite) do not write new data in the same place as old data, 143: * defeating this wiping entirely. Fortunately, such systems 144: * usually don't need a swap file, and for small temp files, they 145: * do write-behind, so if you create and delete a file fast enough, 146: * it never gets written to disk at all. 147: */ 148: 149: /* 150: * The data is randomly generated with the size of the file as a seed. 151: * The data should be random and not leak information. If someone is 152: * examining deleted files, presumably they can reconstruct the file size, 153: * so that's not a secret. H'm... this wiping algorithm makes it easy to, 154: * given a block of data, find the size of the file it came from 155: * and the offset of this block within it. That in turn reveals 156: * something about the state of the disk's allocation tables when the 157: * file was used, possibly making it easier to find other files created 158: * at neaby times - such as plaintext files. Is this acceptable? 159: */ 160: 161: /* 162: * Theory of operation: We use the additive congruential RNG 163: * r[i] = r[i-24] + r[i-55], from Knuth, Vol. 2. This is fast 164: * and has a long enough period that there should be no repetitions 165: * in even a huge file. It is seeded with r[-55] through r[-1] 166: * using another polynomial-based RNG. We seed a linear feedback 167: * shift register (CRC generator) with the size of the swap file, 168: * and clock in 0 bits. Each 32 bits, the value of the generator is 169: * taken as the next integer. This is just to ensure a reasonably 170: * even mix of 1's and 0's in the initialization vector. 171: */ 172: 173: /* 174: * This is the CRC-32 polynomial, which should be okay for random 175: * number generation. 176: * 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 177: * = 1 0000 0100 1100 0001 0001 1101 1011 0111 178: * = 0x04c11db7 179: */ 180: #define POLY 0x04c11db7 181: 1.1.1.6 ! root 182: static void wipeout(FILE * f) 1.1.1.5 root 183: { 1.1.1.6 ! root 184: unsigned *p1, *p2, *p3; ! 185: unsigned long len; ! 186: unsigned long t; ! 187: int i; ! 188: ! 189: /* Get the file size */ ! 190: fseek(f, 0L, SEEK_END); ! 191: len = ftell(f); ! 192: rewind(f); ! 193: ! 194: /* Seed of first RNG. Inverted to get more 1 bits */ ! 195: t = ~len; ! 196: ! 197: /* Initialize first 55 words of buf with pseudo-random stuff */ ! 198: p1 = (unsigned *) textbuf2 + 55; ! 199: do { ! 200: for (i = 0; i < 32; i++) ! 201: t = (t & 0x80000000) ? t << 1 ^ POLY : t << 1; ! 202: *--p1 = (unsigned) t; ! 203: } while (p1 > (unsigned *) textbuf2); ! 204: ! 205: while (len) { ! 206: /* Fill buffer with pseudo-random integers */ ! 207: ! 208: p3 = (unsigned *) textbuf2 + 55; ! 209: p2 = (unsigned *) textbuf2 + 24; ! 210: p1 = (unsigned *) textbuf2 + sizeof(textbuf2) / sizeof(*p1); ! 211: do { ! 212: *--p1 = *--p2 + *--p3; ! 213: } while (p2 > (unsigned *) textbuf2); 1.1.1.5 root 214: 1.1.1.6 ! root 215: p2 = (unsigned *) textbuf2 + sizeof(textbuf2) / sizeof(*p1); ! 216: do { ! 217: *--p1 = *--p2 + *--p3; ! 218: } while (p3 > (unsigned *) textbuf2); 1.1.1.5 root 219: 1.1.1.6 ! root 220: p3 = (unsigned *) textbuf2 + sizeof(textbuf2) / sizeof(*p3); ! 221: do { ! 222: *--p1 = *--p2 + *--p3; ! 223: } while (p1 > (unsigned *) textbuf2); 1.1.1.5 root 224: 1.1.1.6 ! root 225: /* Write it out - yes, we're ignoring errors */ ! 226: if (len > sizeof(textbuf2)) { ! 227: fwrite((char const *) textbuf2, sizeof(textbuf2), 1, f); ! 228: len -= sizeof(textbuf2); ! 229: } else { ! 230: fwrite((char const *) textbuf2, len, 1, f); ! 231: len = 0; ! 232: } ! 233: } 1.1.1.5 root 234: } 235: 236: 237: /* 238: * Completely overwrite and erase file, so that no sensitive 239: * information is left on the disk. 240: */ 1.1.1.6 ! root 241: int wipefile(char *filename) 1.1.1.5 root 242: { 1.1.1.6 ! root 243: FILE *f; ! 244: /* open file f for read/write, in binary (not text) mode... */ ! 245: if ((f = fopen(filename, FOPRWBIN)) == NULL) ! 246: return -1; /* error - file can't be opened */ ! 247: wipeout(f); ! 248: fclose(f); ! 249: return 0; /* normal return */ ! 250: } /* wipefile */ 1.1.1.5 root 251: 252: /* 253: * Returns the part of a filename after all directory specifiers. 254: */ 1.1.1.6 ! root 255: char *file_tail(char *filename) 1.1.1.5 root 256: { 1.1.1.6 ! root 257: char *p; ! 258: char const *s = DIRSEPS; 1.1.1.5 root 259: 1.1.1.6 ! root 260: while (*s) { ! 261: p = strrchr(filename, *s); ! 262: if (p) ! 263: filename = p + 1; ! 264: s++; ! 265: } 1.1.1.5 root 266: 1.1.1.6 ! root 267: return filename; 1.1.1.5 root 268: } 269: 270: 271: /* return TRUE if extension matches the end of filename */ 1.1.1.6 ! root 272: boolean has_extension(char *filename, char *extension) 1.1.1.5 root 273: { 1.1.1.6 ! root 274: int lf = strlen(filename); ! 275: int lx = strlen(extension); 1.1.1.5 root 276: 1.1.1.6 ! root 277: if (lf <= lx) ! 278: return FALSE; ! 279: return !strcmp(filename + lf - lx, extension); 1.1.1.5 root 280: } 281: 282: /* return TRUE if path is a filename created by tempfile() */ 283: /* Filename matches "*.$[0-9][0-9]" */ 1.1.1.6 ! root 284: boolean is_tempfile(char *path) 1.1.1.5 root 285: { 1.1.1.6 ! root 286: char *p = strrchr(path, '.'); ! 287: ! 288: return p != NULL && p[1] == TMP_EXT && ! 289: isdigit(p[2]) && isdigit(p[3]) && p[4] == '\0'; 1.1.1.5 root 290: } 291: 292: /* 293: * Returns TRUE if user left off file extension, allowing default. 294: * Note that the name is misleading if multiple dots are allowed. 295: * not_pgp_extension or something would be better. 296: */ 1.1.1.6 ! root 297: boolean no_extension(char *filename) 1.1.1.5 root 298: { 1.1.1.6 ! root 299: #ifdef MULTIPLE_DOTS /* filename can have more than one dot */ ! 300: if (has_extension(filename, ASC_EXTENSION) || ! 301: has_extension(filename, PGP_EXTENSION) || ! 302: has_extension(filename, SIG_EXTENSION) || ! 303: is_tempfile(filename)) ! 304: return FALSE; ! 305: else ! 306: return TRUE; 1.1.1.5 root 307: #else 1.1.1.6 ! root 308: filename = file_tail(filename); 1.1.1.5 root 309: 1.1.1.6 ! root 310: return strrchr(filename, '.') == NULL; 1.1.1.5 root 311: #endif 1.1.1.6 ! root 312: } /* no_extension */ 1.1.1.5 root 313: 314: 315: /* deletes trailing ".xxx" file extension after the period. */ 1.1.1.6 ! root 316: void drop_extension(char *filename) 1.1.1.5 root 317: { 1.1.1.6 ! root 318: if (!no_extension(filename)) ! 319: *strrchr(filename, '.') = '\0'; ! 320: } /* drop_extension */ 1.1.1.5 root 321: 322: 323: /* append filename extension if there isn't one already. */ 1.1.1.6 ! root 324: void default_extension(char *filename, char *extension) 1.1.1.5 root 325: { 1.1.1.6 ! root 326: if (no_extension(filename)) ! 327: strcat(filename, extension); ! 328: } /* default_extension */ 1.1.1.5 root 329: 330: #ifndef MAX_NAMELEN 331: #if defined(AMIGA) || defined(NeXT) || (defined(BSD) && BSD > 41) || (defined(sun) && defined(i386)) 332: #define MAX_NAMELEN 255 333: #else 334: #include <limits.h> 335: #endif 336: #endif 337: 338: /* truncate the filename so that an extension can be tacked on. */ 1.1.1.6 ! root 339: static void truncate_name(char *path, int ext_len) 1.1.1.5 root 340: { 1.1.1.6 ! root 341: #ifdef UNIX /* for other systems this is a no-op */ ! 342: char *p; ! 343: #ifdef MAX_NAMELEN /* overrides the use of pathconf() */ ! 344: int namemax = MAX_NAMELEN; 1.1.1.5 root 345: #else 1.1.1.6 ! root 346: int namemax; 1.1.1.5 root 347: #ifdef _PC_NAME_MAX 1.1.1.6 ! root 348: char dir[MAX_PATH]; 1.1.1.5 root 349: 1.1.1.6 ! root 350: strcpy(dir, path); ! 351: if ((p = strrchr(dir, '/')) == NULL) { ! 352: strcpy(dir, "."); ! 353: } else { ! 354: if (p == dir) ! 355: ++p; ! 356: *p = '\0'; ! 357: } ! 358: if ((namemax = pathconf(dir, _PC_NAME_MAX)) <= ext_len) ! 359: return; 1.1.1.5 root 360: #else 361: #ifdef NAME_MAX 1.1.1.6 ! root 362: namemax = NAME_MAX; 1.1.1.5 root 363: #else 1.1.1.6 ! root 364: namemax = 14; ! 365: #endif /* NAME_MAX */ ! 366: #endif /* _PC_NAME_MAX */ ! 367: #endif /* MAX_NAMELEN */ ! 368: ! 369: if ((p = strrchr(path, '/')) == NULL) ! 370: p = path; ! 371: else ! 372: ++p; ! 373: if (strlen(p) > namemax - ext_len) { ! 374: if (verbose) ! 375: fprintf(pgpout, "Truncating filename '%s' ", path); ! 376: p[namemax - ext_len] = '\0'; ! 377: if (verbose) ! 378: fprintf(pgpout, "to '%s'\n", path); ! 379: } ! 380: #endif /* UNIX */ 1.1.1.5 root 381: } 382: 383: /* change the filename extension. */ 1.1.1.6 ! root 384: void force_extension(char *filename, char *extension) 1.1.1.5 root 385: { 1.1.1.6 ! root 386: drop_extension(filename); /* out with the old */ ! 387: truncate_name(filename, strlen(extension)); ! 388: strcat(filename, extension); /* in with the new */ ! 389: } /* force_extension */ 1.1.1.5 root 390: 391: 392: /* 393: * Get yes/no answer from user, returns TRUE for yes, FALSE for no. 394: * First the translations are checked, if they don't match 'y' and 'n' 395: * are tried. 396: */ 1.1.1.6 ! root 397: boolean getyesno(char default_answer) 1.1.1.5 root 398: { 1.1.1.6 ! root 399: char buf[8]; ! 400: static char yes[8], no[8]; 1.1.1.5 root 401: 1.1.1.6 ! root 402: if (yes[0] == '\0') { ! 403: strncpy(yes, LANG("y"), 7); ! 404: strncpy(no, LANG("n"), 7); ! 405: } ! 406: if (!batchmode) { /* return default answer in batchmode */ ! 407: getstring(buf, 6, TRUE); /* echo keyboard input */ ! 408: strlwr(buf); ! 409: if (!strncmp(buf, no, strlen(no))) ! 410: return FALSE; ! 411: if (!strncmp(buf, yes, strlen(yes))) ! 412: return TRUE; ! 413: if (buf[0] == 'n') ! 414: return FALSE; ! 415: if (buf[0] == 'y') ! 416: return TRUE; ! 417: } ! 418: return default_answer == 'y' ? TRUE : FALSE; ! 419: } /* getyesno */ 1.1.1.5 root 420: 421: /* if user consents to it, change the filename extension. */ 1.1.1.6 ! root 422: char *maybe_force_extension(char *filename, char *extension) 1.1.1.5 root 423: { 1.1.1.6 ! root 424: static char newname[MAX_PATH]; ! 425: if (!has_extension(filename, extension)) { ! 426: strcpy(newname, filename); ! 427: force_extension(newname, extension); ! 428: if (!file_exists(newname)) { ! 429: fprintf(pgpout, LANG("\nShould '%s' be renamed to '%s' [Y/n]? "), ! 430: filename, newname); ! 431: if (getyesno('y')) ! 432: return newname; ! 433: } ! 434: } ! 435: return NULL; ! 436: } /* maybe_force_extension */ 1.1.1.5 root 437: 438: /* 439: * Add a trailing directory separator to a name, if absent. 440: */ 1.1.1.6 ! root 441: static void addslash(char *name) 1.1.1.5 root 442: { 1.1.1.6 ! root 443: int i = strlen(name); 1.1.1.5 root 444: 1.1.1.6 ! root 445: if (i != 0 && !strchr(DIRSEPS, name[i - 1])) { ! 446: name[i] = DIRSEPS[0]; ! 447: name[i + 1] = '\0'; ! 448: } 1.1.1.5 root 449: } 450: 451: /* 452: * Builds a filename with a complete path specifier from the environmental 453: * variable PGPPATH. 454: */ 1.1.1.6 ! root 455: char *buildfilename(char *result, char *fname) 1.1.1.5 root 456: { 1.1.1.6 ! root 457: char const *s = getenv(PGPPATH); 1.1.1.5 root 458: 1.1.1.6 ! root 459: result[0] = '\0'; 1.1.1.5 root 460: 1.1.1.6 ! root 461: if (s && strlen(s) <= 50) { ! 462: strcpy(result, s); ! 463: } 1.1.1.5 root 464: #ifdef UNIX 1.1.1.6 ! root 465: /* On Unix, default to $HOME/.pgp, otherwise, current directory. */ ! 466: else { ! 467: s = getenv("HOME"); ! 468: if (s && strlen(s) <= 50) { ! 469: strcpy(result, s); ! 470: addslash(result); ! 471: strcat(result, ".pgp"); ! 472: } ! 473: } ! 474: #endif /* UNIX */ ! 475: ! 476: addslash(result); ! 477: strcat(result, fname); ! 478: return result; ! 479: } /* buildfilename */ 1.1.1.5 root 480: 481: char *buildsysfilename(char *result, char *fname) 482: { 1.1.1.6 ! root 483: buildfilename(result, fname); 1.1.1.5 root 484: #ifdef PGP_SYSTEM_DIR 1.1.1.6 ! root 485: if (file_exists(result)) ! 486: return result; ! 487: strcpy(result, PGP_SYSTEM_DIR); ! 488: strcat(result, fname); ! 489: if (file_exists(result)) 1.1.1.5 root 490: return result; 1.1.1.6 ! root 491: buildfilename(result, fname); /* Put name back for error */ ! 492: #endif ! 493: return result; 1.1.1.5 root 494: } 495: 496: 497: /* Convert filename to canonical form, with slashes as separators */ 1.1.1.6 ! root 498: void file_to_canon(char *filename) 1.1.1.5 root 499: { 500: #ifdef BSLASH 1.1.1.6 ! root 501: while (*filename) { ! 502: if (*filename == '\\') ! 503: *filename = '/'; ! 504: ++filename; ! 505: } 1.1.1.5 root 506: #endif 507: } 508: 509: 1.1.1.6 ! root 510: int write_error(FILE * f) 1.1.1.5 root 511: { 1.1.1.6 ! root 512: fflush(f); ! 513: if (ferror(f)) { 1.1.1.5 root 514: #ifdef ENOSPC 1.1.1.6 ! root 515: if (errno == ENOSPC) ! 516: fprintf(pgpout, LANG("\nDisk full.\n")); ! 517: else 1.1.1.5 root 518: #endif 1.1.1.6 ! root 519: fprintf(pgpout, LANG("\nFile write error.\n")); ! 520: return -1; ! 521: } ! 522: return 0; 1.1.1.5 root 523: } 524: 525: /* copy file f to file g, for longcount bytes */ 1.1.1.6 ! root 526: int copyfile(FILE * f, FILE * g, word32 longcount) 1.1.1.5 root 527: { 1.1.1.6 ! root 528: int count, status = 0; ! 529: do { /* read and write the whole file... */ ! 530: if (longcount < (word32) DISKBUFSIZE) ! 531: count = (int) longcount; ! 532: else ! 533: count = DISKBUFSIZE; ! 534: count = fread(textbuf, 1, count, f); ! 535: if (count > 0) { ! 536: if (CONVERSION != NO_CONV) { ! 537: int i; ! 538: for (i = 0; i < count; i++) ! 539: textbuf[i] = (CONVERSION == EXT_CONV) ? ! 540: EXT_C(textbuf[i]) : ! 541: INT_C(textbuf[i]); ! 542: } ! 543: if (fwrite(textbuf, 1, count, g) != count) { ! 544: /* Problem: return error value */ ! 545: status = -1; ! 546: break; ! 547: } ! 548: longcount -= count; ! 549: } ! 550: /* if text block was short, exit loop */ ! 551: } while (count == DISKBUFSIZE); ! 552: burn(textbuf); /* burn sensitive data on stack */ ! 553: return status; ! 554: } /* copyfile */ 1.1.1.5 root 555: 556: /* 557: * Like copyfile, but takes a position for file f. Returns with 558: * f and g pointing just past the copied data. 559: */ 1.1.1.6 ! root 560: int copyfilepos(FILE * f, FILE * g, word32 longcount, word32 fpos) 1.1.1.5 root 561: { 1.1.1.6 ! root 562: fseek(f, fpos, SEEK_SET); ! 563: return copyfile(f, g, longcount); 1.1.1.5 root 564: } 565: 566: 567: /* copy file f to file g, for longcount bytes. Convert to 568: * canonical form as we go. f is open in text mode. Canonical 569: * form uses crlf's as line separators. 570: */ 1.1.1.6 ! root 571: int copyfile_to_canon(FILE * f, FILE * g, word32 longcount) 1.1.1.5 root 572: { 1.1.1.6 ! root 573: int count, status = 0; ! 574: byte c, *tb1, *tb2; ! 575: int i, nbytes; ! 576: int nspaces = 0; ! 577: do { /* read and write the whole file... */ ! 578: if (longcount < (word32) DISKBUFSIZE) ! 579: count = (int) longcount; ! 580: else ! 581: count = DISKBUFSIZE; ! 582: count = fread(textbuf, 1, count, f); ! 583: if (count > 0) { ! 584: /* Convert by adding CR before LF */ ! 585: tb1 = textbuf; ! 586: tb2 = (byte *) textbuf2; ! 587: for (i = 0; i < count; ++i) { ! 588: switch (CONVERSION) { ! 589: case EXT_CONV: ! 590: c = EXT_C(*tb1++); ! 591: break; ! 592: case INT_CONV: ! 593: c = INT_C(*tb1++); ! 594: break; ! 595: default: ! 596: c = *tb1++; ! 597: } ! 598: if (strip_spaces) { ! 599: if (c == ' ') { ! 600: /* Don't output spaces yet */ ! 601: nspaces += 1; ! 602: } else { ! 603: if (c == '\n') { ! 604: *tb2++ = '\r'; ! 605: nspaces = 0; /* Delete trailing spaces */ 1.1.1.5 root 606: } 1.1.1.6 ! root 607: if (nspaces) { ! 608: /* Put out spaces now */ ! 609: do ! 610: *tb2++ = ' '; ! 611: while (--nspaces); 1.1.1.5 root 612: } 1.1.1.6 ! root 613: *tb2++ = c; ! 614: } ! 615: } else { ! 616: if (c == '\n') ! 617: *tb2++ = '\r'; ! 618: *tb2++ = c; 1.1.1.5 root 619: } 1.1.1.6 ! root 620: } ! 621: nbytes = tb2 - (byte *) textbuf2; ! 622: if (fwrite(textbuf2, 1, nbytes, g) != nbytes) { ! 623: /* Problem: return error value */ ! 624: status = -1; ! 625: break; ! 626: } ! 627: longcount -= count; ! 628: } ! 629: /* if text block was short, exit loop */ ! 630: } while (count == DISKBUFSIZE); ! 631: burn(textbuf); /* burn sensitive data on stack */ ! 632: burn(textbuf2); ! 633: return status; ! 634: } /* copyfile_to_canon */ 1.1.1.5 root 635: 636: 637: /* copy file f to file g, for longcount bytes. Convert from 638: * canonical to local form as we go. g is open in text mode. Canonical 639: * form uses crlf's as line separators. 640: */ 1.1.1.6 ! root 641: int copyfile_from_canon(FILE * f, FILE * g, word32 longcount) 1.1.1.5 root 642: { 1.1.1.6 ! root 643: int count, status = 0; ! 644: byte c, *tb1, *tb2; ! 645: int i, nbytes; ! 646: do { /* read and write the whole file... */ ! 647: if (longcount < (word32) DISKBUFSIZE) ! 648: count = (int) longcount; ! 649: else ! 650: count = DISKBUFSIZE; ! 651: count = fread(textbuf, 1, count, f); ! 652: if (count > 0) { ! 653: /* Convert by removing CR's */ ! 654: tb1 = textbuf; ! 655: tb2 = (byte *) textbuf2; ! 656: for (i = 0; i < count; ++i) { ! 657: switch (CONVERSION) { ! 658: case EXT_CONV: ! 659: c = EXT_C(*tb1++); ! 660: break; ! 661: case INT_CONV: ! 662: c = INT_C(*tb1++); ! 663: break; ! 664: default: ! 665: c = *tb1++; 1.1.1.5 root 666: } 1.1.1.6 ! root 667: if (c != '\r') ! 668: *tb2++ = c; ! 669: } ! 670: nbytes = tb2 - (byte *) textbuf2; ! 671: if (fwrite(textbuf2, 1, nbytes, g) != nbytes) { ! 672: /* Problem: return error value */ ! 673: status = -1; ! 674: break; ! 675: } ! 676: longcount -= count; ! 677: } ! 678: /* if text block was short, exit loop */ ! 679: } while (count == DISKBUFSIZE); ! 680: burn(textbuf); /* burn sensitive data on stack */ ! 681: burn(textbuf2); ! 682: return status; ! 683: } /* copyfile_from_canon */ 1.1.1.5 root 684: 1.1.1.6 ! root 685: /* Copy srcFile to destFile */ 1.1.1.5 root 686: int copyfiles_by_name(char *srcFile, char *destFile) 687: { 1.1.1.6 ! root 688: FILE *f, *g; ! 689: int status = 0; ! 690: long fileLength; ! 691: ! 692: f = fopen(srcFile, FOPRBIN); ! 693: if (f == NULL) ! 694: return -1; ! 695: g = fopen(destFile, FOPWBIN); ! 696: if (g == NULL) { 1.1.1.5 root 697: fclose(f); 1.1.1.6 ! root 698: return -1; ! 699: } ! 700: /* Get file length and copy it */ ! 701: fseek(f, 0L, SEEK_END); ! 702: fileLength = ftell(f); ! 703: rewind(f); ! 704: status = copyfile(f, g, fileLength); ! 705: fclose(f); ! 706: if (write_error(g)) ! 707: status = -1; ! 708: fclose(g); ! 709: return status; ! 710: } /* copyfiles_by_name */ 1.1.1.5 root 711: 712: /* Copy srcFile to destFile, converting to canonical text form */ 1.1.1.6 ! root 713: int make_canonical(char *srcFile, char *destFile) 1.1.1.5 root 714: { 1.1.1.6 ! root 715: FILE *f, *g; ! 716: int status = 0; ! 717: long fileLength; ! 718: ! 719: if (((f = fopen(srcFile, FOPRTXT)) == NULL) || ! 720: ((g = fopen(destFile, FOPWBIN)) == NULL)) ! 721: /* Can't open files */ ! 722: return -1; ! 723: ! 724: /* Get file length and copy it */ ! 725: fseek(f, 0L, SEEK_END); ! 726: fileLength = ftell(f); ! 727: rewind(f); ! 728: CONVERSION = INT_CONV; ! 729: status = copyfile_to_canon(f, g, fileLength); ! 730: CONVERSION = NO_CONV; ! 731: fclose(f); ! 732: if (write_error(g)) ! 733: status = -1; ! 734: fclose(g); ! 735: return status; ! 736: } /* make_canonical */ 1.1.1.5 root 737: 738: /* 739: * Like rename() but will try to copy the file if the rename fails. 740: * This is because under OS's with multiple physical volumes if the 741: * source and destination are on different volumes the rename will fail 742: */ 1.1.1.6 ! root 743: int rename2(char *srcFile, char *destFile) 1.1.1.5 root 744: { 1.1.1.6 ! root 745: FILE *f, *g; ! 746: int status = 0; ! 747: long fileLength; 1.1.1.5 root 748: 749: #ifdef VMS 1.1.1.6 ! root 750: if (rename(srcFile, destFile) != 0) 1.1.1.5 root 751: #else 1.1.1.6 ! root 752: if (rename(srcFile, destFile) == -1) 1.1.1.5 root 753: #endif 1.1.1.6 ! root 754: { ! 755: /* Rename failed, try a copy */ ! 756: if (((f = fopen(srcFile, FOPRBIN)) == NULL) || ! 757: ((g = fopen(destFile, FOPWBIN)) == NULL)) ! 758: /* Can't open files */ ! 759: return -1; ! 760: ! 761: /* Get file length and copy it */ ! 762: fseek(f, 0L, SEEK_END); ! 763: fileLength = ftell(f); ! 764: rewind(f); ! 765: status = copyfile(f, g, fileLength); ! 766: if (write_error(g)) ! 767: status = -1; ! 768: ! 769: /* Zap source file if the copy went OK, otherwise zap the (possibly ! 770: incomplete) destination file */ ! 771: if (status >= 0) { ! 772: wipeout(f); /* Zap source file */ ! 773: fclose(f); ! 774: remove(srcFile); ! 775: fclose(g); ! 776: } else { ! 777: if (is_regular_file(destFile)) { ! 778: wipeout(g); /* Zap destination file */ ! 779: fclose(g); ! 780: remove(destFile); ! 781: } else { ! 782: fclose(g); ! 783: } ! 784: fclose(f); 1.1.1.5 root 785: } 1.1.1.6 ! root 786: } ! 787: return status; 1.1.1.5 root 788: } 789: 790: /* read the data from stdin to the phantom input file */ 1.1.1.6 ! root 791: int readPhantomInput(char *filename) 1.1.1.5 root 792: { 1.1.1.6 ! root 793: FILE *outFilePtr; ! 794: byte buffer[512]; ! 795: int bytesRead, status = 0; ! 796: ! 797: if (verbose) ! 798: fprintf(pgpout, "writing stdin to file %s\n", filename); ! 799: if ((outFilePtr = fopen(filename, FOPWBIN)) == NULL) ! 800: return -1; 1.1.1.5 root 801: 802: #if defined(MSDOS) || defined(OS2) 1.1.1.6 ! root 803: /* Under DOS must set input stream to binary mode to avoid data mangling */ ! 804: setmode(fileno(stdin), O_BINARY); ! 805: #endif /* MSDOS || OS2 */ ! 806: while ((bytesRead = fread(buffer, 1, 512, stdin)) > 0) ! 807: if (fwrite(buffer, 1, bytesRead, outFilePtr) != bytesRead) { ! 808: status = -1; ! 809: break; ! 810: } ! 811: if (write_error(outFilePtr)) ! 812: status = -1; ! 813: fclose(outFilePtr); 1.1.1.5 root 814: #if defined(MSDOS) || defined(OS2) 1.1.1.6 ! root 815: setmode(fileno(stdin), O_TEXT); /* Reset stream */ ! 816: #endif /* MSDOS || OS2 */ ! 817: return status; 1.1.1.5 root 818: } 819: 820: /* write the data from the phantom output file to stdout */ 1.1.1.6 ! root 821: int writePhantomOutput(char *filename) ! 822: { ! 823: FILE *outFilePtr; ! 824: byte buffer[512]; ! 825: int bytesRead, status = 0; ! 826: ! 827: if (verbose) ! 828: fprintf(pgpout, "writing file %s to stdout\n", filename); ! 829: /* this can't fail since we just created the file */ ! 830: outFilePtr = fopen(filename, FOPRBIN); 1.1.1.5 root 831: 832: #if defined(MSDOS) || defined(OS2) 1.1.1.6 ! root 833: setmode(fileno(stdout), O_BINARY); ! 834: #endif /* MSDOS || OS2 */ ! 835: while ((bytesRead = fread(buffer, 1, 512, outFilePtr)) > 0) ! 836: if (fwrite(buffer, 1, bytesRead, stdout) != bytesRead) { ! 837: status = -1; ! 838: break; ! 839: } ! 840: fclose(outFilePtr); ! 841: fflush(stdout); ! 842: if (ferror(stdout)) { ! 843: status = -1; ! 844: fprintf(pgpout, LANG("\007Write error on stdout.\n")); ! 845: } 1.1.1.5 root 846: #if defined(MSDOS) || defined(OS2) 1.1.1.6 ! root 847: setmode(fileno(stdout), O_TEXT); ! 848: #endif /* MSDOS || OS2 */ 1.1.1.5 root 849: 1.1.1.6 ! root 850: return status; 1.1.1.5 root 851: } 852: 853: /* Return the size from the current position of file f to the end */ 1.1.1.6 ! root 854: word32 fsize(FILE * f) 1.1.1.5 root 855: { 1.1.1.6 ! root 856: long fpos = ftell(f); ! 857: long fpos2; 1.1.1.5 root 858: 1.1.1.6 ! root 859: fseek(f, 0L, SEEK_END); ! 860: fpos2 = ftell(f); ! 861: fseek(f, fpos, SEEK_SET); ! 862: return (word32) (fpos2 - fpos); 1.1.1.5 root 863: } 864: 865: /* Return TRUE if file filename looks like a pure text file */ 1.1.1.6 ! root 866: int is_text_file(char *filename) 1.1.1.5 root 867: { 1.1.1.6 ! root 868: FILE *f = fopen(filename, "r"); /* FOPRBIN gives problem with VMS */ ! 869: int i, n, bit8 = 0; ! 870: unsigned char buf[512]; ! 871: unsigned char *bufptr = buf; ! 872: unsigned char c; ! 873: ! 874: if (!f) ! 875: return FALSE; /* error opening it, so not a text file */ ! 876: i = n = fread(buf, 1, sizeof(buf), f); ! 877: fclose(f); ! 878: if (n <= 0) ! 879: return FALSE; /* empty file or error, not a text file */ ! 880: if (compressSignature(buf) >= 0) ! 881: return FALSE; ! 882: while (i--) { ! 883: c = *bufptr++; ! 884: if (c & 0x80) ! 885: ++bit8; ! 886: else /* allow BEL BS HT LF VT FF CR EOF control characters */ ! 887: if (c < '\007' || (c > '\r' && c < ' ' && c != '\032')) ! 888: return FALSE; /* not a text file */ ! 889: } ! 890: if (strcmp(language, "ru") == 0) ! 891: return TRUE; ! 892: /* assume binary if more than 1/4 bytes have 8th bit set */ ! 893: return bit8 < n / 4; ! 894: } /* is_text_file */ 1.1.1.5 root 895: 896: VOID *xmalloc(unsigned size) 1.1.1.6 ! root 897: { ! 898: VOID *p; ! 899: if (size == 0) ! 900: ++size; ! 901: p = malloc(size); ! 902: if (p == NULL) { ! 903: fprintf(stderr, LANG("\n\007Out of memory.\n")); ! 904: exitPGP(1); ! 905: } ! 906: return p; 1.1.1.5 root 907: } 908: 909: /*---------------------------------------------------------------------- 910: * temporary file routines 911: */ 912: 913: 914: #define MAXTMPF 8 915: 916: #define TMP_INUSE 2 917: 1.1.1.6 ! root 918: static struct { ! 919: char path[MAX_PATH]; ! 920: int flags; ! 921: int num; 1.1.1.5 root 922: } tmpf[MAXTMPF]; 923: 924: static char tmpdir[256]; /* temporary file directory */ 925: static char outdir[256]; /* output directory */ 1.1.1.6 ! root 926: static char tmpbasename[64] = "pgptemp"; /* basename for ! 927: temporary files */ 1.1.1.5 root 928: 929: 930: /* 931: * set directory for temporary files. path will be stored in 932: * tmpdir[] with an appropriate trailing path separator. 933: */ 934: void settmpdir(char *path) 935: { 1.1.1.6 ! root 936: char *p; 1.1.1.5 root 937: 1.1.1.6 ! root 938: if (path == NULL || *path == '\0') { ! 939: tmpdir[0] = '\0'; ! 940: return; ! 941: } ! 942: strcpy(tmpdir, path); ! 943: p = tmpdir + strlen(tmpdir) - 1; ! 944: if (*p != '/' && *p != '\\' && *p != ']' && *p != ':') { ! 945: /* append path separator, either / or \ */ ! 946: if ((p = strchr(tmpdir, '/')) == NULL && ! 947: (p = strchr(tmpdir, '\\')) == NULL) ! 948: p = "/"; /* path did not contain / or \, use / */ ! 949: strncat(tmpdir, p, 1); ! 950: } 1.1.1.5 root 951: } 952: 953: /* 954: * set output directory to avoid a file copy when temp file is renamed to 955: * output file. the argument filename must be a valid path for a file, not 956: * a directory. 957: */ 958: void setoutdir(char *filename) 959: { 1.1.1.6 ! root 960: char *p; 1.1.1.5 root 961: 1.1.1.6 ! root 962: if (filename == NULL) { ! 963: strcpy(outdir, tmpdir); ! 964: return; ! 965: } ! 966: strcpy(outdir, filename); ! 967: p = file_tail(outdir); ! 968: strcpy(tmpbasename, p); ! 969: *p = '\0'; ! 970: drop_extension(tmpbasename); 1.1.1.5 root 971: #if !defined(BSD42) && !defined(BSD43) && !defined(sun) 1.1.1.6 ! root 972: /* ! 973: * we don't depend on pathconf here, if it returns an incorrect value ! 974: * for NAME_MAX (like Linux 0.97 with minix FS) finding a unique name ! 975: * for temp files can fail. ! 976: */ ! 977: tmpbasename[10] = '\0'; /* 14 char limit */ 1.1.1.5 root 978: #endif 979: } 980: 981: /* 982: * return a unique temporary file name 983: */ 984: char *tempfile(int flags) 985: { 1.1.1.6 ! root 986: int i, j; ! 987: int num; ! 988: int fd; 1.1.1.5 root 989: #ifndef UNIX 1.1.1.6 ! root 990: FILE *fp; 1.1.1.5 root 991: #endif 992: 1.1.1.6 ! root 993: for (i = 0; i < MAXTMPF; ++i) ! 994: if (tmpf[i].flags == 0) ! 995: break; 1.1.1.5 root 996: 1.1.1.6 ! root 997: if (i == MAXTMPF) { ! 998: /* message only for debugging, no need for LANG */ ! 999: fprintf(stderr, "\n\007Out of temporary files\n"); ! 1000: return NULL; ! 1001: } ! 1002: again: ! 1003: num = 0; ! 1004: do { ! 1005: for (j = 0; j < MAXTMPF; ++j) ! 1006: if (tmpf[j].flags && tmpf[j].num == num) ! 1007: break; ! 1008: if (j < MAXTMPF) ! 1009: continue; /* sequence number already in use */ ! 1010: sprintf(tmpf[i].path, "%s%s.%c%02d", ! 1011: ((flags & TMP_TMPDIR) && *tmpdir ? tmpdir : outdir), ! 1012: tmpbasename, TMP_EXT, num); ! 1013: if (!file_exists(tmpf[i].path)) ! 1014: break; ! 1015: } ! 1016: while (++num < 100); 1.1.1.5 root 1017: 1.1.1.6 ! root 1018: if (num == 100) { ! 1019: fprintf(pgpout, "\n\007tempfile: cannot find unique name\n"); ! 1020: return NULL; ! 1021: } 1.1.1.5 root 1022: #if defined(UNIX) || defined(VMS) 1.1.1.6 ! root 1023: if ((fd = open(tmpf[i].path, O_EXCL | O_RDWR | O_CREAT, 0600)) != -1) ! 1024: close(fd); 1.1.1.5 root 1025: #else 1.1.1.6 ! root 1026: if ((fp = fopen(tmpf[i].path, "w")) != NULL) ! 1027: fclose(fp); ! 1028: fd = (fp == NULL ? -1 : 0); 1.1.1.5 root 1029: #endif 1030: 1.1.1.6 ! root 1031: if (fd == -1) { ! 1032: if (!(flags & TMP_TMPDIR)) { ! 1033: flags |= TMP_TMPDIR; ! 1034: goto again; 1.1.1.5 root 1035: } 1.1.1.6 ! root 1036: #ifdef UNIX ! 1037: else if (tmpdir[0] == '\0') { ! 1038: strcpy(tmpdir, "/tmp/"); ! 1039: goto again; 1.1.1.5 root 1040: } 1.1.1.6 ! root 1041: #endif ! 1042: } ! 1043: if (fd == -1) { ! 1044: fprintf(pgpout, LANG("\n\007Cannot create temporary file '%s'\n"), ! 1045: tmpf[i].path); ! 1046: user_error(); ! 1047: } 1.1.1.5 root 1048: #ifdef VMS 1.1.1.6 ! root 1049: remove(tmpf[i].path); 1.1.1.5 root 1050: #endif 1051: 1.1.1.6 ! root 1052: tmpf[i].num = num; ! 1053: tmpf[i].flags = flags | TMP_INUSE; ! 1054: if (verbose) ! 1055: fprintf(pgpout, "tempfile: created '%s'\n", tmpf[i].path); ! 1056: return tmpf[i].path; ! 1057: } /* tempfile */ 1.1.1.5 root 1058: 1059: /* 1060: * remove temporary file, wipe if necessary. 1061: */ 1062: void rmtemp(char *name) 1063: { 1.1.1.6 ! root 1064: int i; 1.1.1.5 root 1065: 1.1.1.6 ! root 1066: for (i = 0; i < MAXTMPF; ++i) ! 1067: if (tmpf[i].flags && strcmp(tmpf[i].path, name) == 0) ! 1068: break; ! 1069: ! 1070: if (i < MAXTMPF) { ! 1071: if (strlen(name) > 3 && name[strlen(name) - 3] == TMP_EXT) { ! 1072: /* only remove file if name hasn't changed */ ! 1073: if (verbose) ! 1074: fprintf(pgpout, "rmtemp: removing '%s'\n", name); ! 1075: if (tmpf[i].flags & TMP_WIPE) ! 1076: wipefile(name); ! 1077: if (!remove(name)) { ! 1078: tmpf[i].flags = 0; ! 1079: } else if (verbose) { ! 1080: fprintf(stderr, "\nrmtemp: Failed to remove %s", name); ! 1081: perror("\nError"); ! 1082: } ! 1083: } else if (verbose) ! 1084: fprintf(pgpout, "rmtemp: not removing '%s'\n", name); ! 1085: } ! 1086: } /* rmtemp */ 1.1.1.5 root 1087: 1088: /* 1089: * make temporary file permanent, returns the new name. 1090: */ 1091: char *savetemp(char *name, char *newname) 1092: { 1.1.1.6 ! root 1093: int i, overwrite; ! 1094: static char buf[MAX_PATH]; 1.1.1.5 root 1095: 1.1.1.6 ! root 1096: if (strcmp(name, newname) == 0) ! 1097: return name; 1.1.1.5 root 1098: 1.1.1.6 ! root 1099: for (i = 0; i < MAXTMPF; ++i) ! 1100: if (tmpf[i].flags && strcmp(tmpf[i].path, name) == 0) ! 1101: break; ! 1102: ! 1103: if (i < MAXTMPF) { ! 1104: if (strlen(name) < 4 || name[strlen(name) - 3] != TMP_EXT) { ! 1105: if (verbose) ! 1106: fprintf(pgpout, "savetemp: not renaming '%s' to '%s'\n", ! 1107: name, newname); ! 1108: return name; /* return original file name */ ! 1109: } ! 1110: } ! 1111: while (file_exists(newname)) { ! 1112: if (batchmode && !force_flag) { ! 1113: fprintf(pgpout, LANG("\n\007Output file '%s' already exists.\n"), ! 1114: newname); ! 1115: return NULL; ! 1116: } ! 1117: if (is_regular_file(newname)) { ! 1118: if (force_flag) { ! 1119: /* remove without asking */ ! 1120: remove(newname); ! 1121: break; ! 1122: } ! 1123: fprintf(pgpout, ! 1124: LANG("\n\007Output file '%s' already exists. Overwrite (y/N)? "), ! 1125: newname); ! 1126: overwrite = getyesno('n'); ! 1127: } else { ! 1128: fprintf(pgpout, ! 1129: LANG("\n\007Output file '%s' already exists.\n"), newname); ! 1130: if (force_flag) /* never remove special file */ ! 1131: return NULL; ! 1132: overwrite = FALSE; 1.1.1.5 root 1133: } 1134: 1.1.1.6 ! root 1135: if (!overwrite) { ! 1136: fprintf(pgpout, LANG("\nEnter new file name: ")); ! 1137: getstring(buf, MAX_PATH - 1, TRUE); ! 1138: if (buf[0] == '\0') 1.1.1.5 root 1139: return NULL; 1.1.1.6 ! root 1140: newname = buf; ! 1141: } else { ! 1142: remove(newname); 1.1.1.5 root 1143: } 1.1.1.6 ! root 1144: } ! 1145: if (verbose) ! 1146: fprintf(pgpout, "savetemp: renaming '%s' to '%s'\n", name, newname); ! 1147: if (rename2(name, newname) < 0) { ! 1148: /* errorLvl = UNKNOWN_FILE_ERROR; */ ! 1149: fprintf(pgpout, LANG("Can't create output file '%s'\n"), newname); ! 1150: return NULL; ! 1151: } ! 1152: if (i < MAXTMPF) ! 1153: tmpf[i].flags = 0; ! 1154: return newname; ! 1155: } /* savetemp */ 1.1.1.5 root 1156: 1157: /* 1158: * like savetemp(), only make backup of destname if it exists 1159: */ 1160: int savetempbak(char *tmpname, char *destname) 1161: { 1.1.1.6 ! root 1162: char bakpath[MAX_PATH]; 1.1.1.5 root 1163: #ifdef UNIX 1.1.1.6 ! root 1164: int mode = -1; 1.1.1.5 root 1165: #endif 1166: 1.1.1.6 ! root 1167: if (is_tempfile(destname)) { ! 1168: remove(destname); ! 1169: } else { ! 1170: if (file_exists(destname)) { 1.1.1.5 root 1171: #ifdef UNIX 1.1.1.6 ! root 1172: struct stat st; ! 1173: if (stat(destname, &st) != -1) ! 1174: mode = st.st_mode & 07777; ! 1175: #endif ! 1176: strcpy(bakpath, destname); ! 1177: force_extension(bakpath, BAK_EXTENSION); ! 1178: remove(bakpath); 1.1.1.5 root 1179: #ifdef VMS 1.1.1.6 ! root 1180: if (rename(destname, bakpath) != 0) 1.1.1.5 root 1181: #else 1.1.1.6 ! root 1182: if (rename(destname, bakpath) == -1) 1.1.1.5 root 1183: #endif 1184: return -1; 1.1.1.6 ! root 1185: } ! 1186: } ! 1187: if (savetemp(tmpname, destname) == NULL) ! 1188: return -1; 1.1.1.5 root 1189: #ifdef UNIX 1.1.1.6 ! root 1190: if (mode != -1) ! 1191: chmod(destname, mode); 1.1.1.5 root 1192: #endif 1.1.1.6 ! root 1193: return 0; 1.1.1.5 root 1194: } 1195: 1196: /* 1197: * remove all temporary files and wipe them if necessary 1198: */ 1199: void cleanup_tmpf(void) 1200: { 1.1.1.6 ! root 1201: int i; 1.1.1.5 root 1202: 1.1.1.6 ! root 1203: for (i = 0; i < MAXTMPF; ++i) ! 1204: if (tmpf[i].flags) ! 1205: rmtemp(tmpf[i].path); ! 1206: } /* cleanup_tmpf */ 1.1.1.5 root 1207: 1208: /* 1209: * Routines to search for the manuals. 1210: * 1211: * Why all this code? 1212: * 1213: * Some dimwits have been distributing versions of PGP (especially on MS-DOS) 1214: * without the manuals. This frustrates users (who call Philip Zimmermann 1215: * at all hours of the day and night), and in addition to depriving them 1216: * of instructions on how to operate the program, also deprives them of 1217: * IMPORTANT legal notices. This is a Bad Thing, so we've gone to the 1218: * trouble of being fascist and *forcing* the manuals to be there. 1219: */ 1.1.1.6 ! root 1220: static unsigned ext_missing(char *prefix) 1.1.1.5 root 1221: { 1.1.1.6 ! root 1222: static char const *const extensions[] = ! 1223: { 1.1.1.5 root 1224: #ifdef VMS 1.1.1.6 ! root 1225: ".doc", ".txt", ".man", ".tex", ".", 0}; 1.1.1.5 root 1226: #else 1.1.1.6 ! root 1227: ".doc", ".txt", ".man", ".tex", "", 0}; 1.1.1.5 root 1228: #endif 1.1.1.6 ! root 1229: char const *const *p; ! 1230: char *end = prefix + strlen(prefix); 1.1.1.5 root 1231: 1.1.1.6 ! root 1232: for (p = extensions; *p; p++) { ! 1233: strcpy(end, *p); ! 1234: #if 0 /* Debugging code */ ! 1235: fprintf(pgpout, "Looking for \"%s\"\n", prefix); ! 1236: #endif ! 1237: if (file_exists(prefix)) ! 1238: return 0; ! 1239: } ! 1240: return 1; 1.1.1.5 root 1241: } 1242: 1243: /* 1244: * Returns mask of files missing 1245: */ 1.1.1.6 ! root 1246: static unsigned files_missing(char *prefix) 1.1.1.5 root 1247: { 1.1.1.6 ! root 1248: static char const *const names[] = ! 1249: {"pgpdoc1", "pgpdoc2", 0}; ! 1250: char const *const *p; ! 1251: unsigned bit, mask = 3; ! 1252: int len = strlen(prefix); 1.1.1.5 root 1253: 1.1.1.6 ! root 1254: if (prefix[0] && !file_exists(prefix)) /* Directory doesn't exist? */ ! 1255: return mask; ! 1256: if (len && strchr(DIRSEPS, prefix[len - 1]) == 0) ! 1257: prefix[len++] = DIRSEPS[0]; ! 1258: for (p = names, bit = 1; *p; p++, bit <<= 1) { ! 1259: strcpy(prefix + len, *p); ! 1260: if (!ext_missing(prefix)) ! 1261: mask &= ~bit; ! 1262: } ! 1263: ! 1264: return mask; /* Bitmask of which files exist */ 1.1.1.5 root 1265: } 1266: 1267: /* 1268: * Search prefix directory and doc subdirectory. 1269: */ 1.1.1.6 ! root 1270: static unsigned doc_missing(char *prefix) 1.1.1.5 root 1271: { 1.1.1.6 ! root 1272: unsigned mask; ! 1273: int len = strlen(prefix); 1.1.1.5 root 1274: 1.1.1.6 ! root 1275: mask = files_missing(prefix); ! 1276: if (!mask) ! 1277: return 0; 1.1.1.5 root 1278: #ifdef VMS 1.1.1.6 ! root 1279: if (len && prefix[len - 1] == ']') { ! 1280: strcpy(prefix + len - 1, ".doc]"); ! 1281: } else { ! 1282: assert(!len || prefix[len - 1] == ':'); ! 1283: strcpy(prefix + len, "[doc]"); ! 1284: } ! 1285: #else ! 1286: if (len && prefix[len - 1] != DIRSEPS[0]) ! 1287: prefix[len++] = DIRSEPS[0]; ! 1288: strcpy(prefix + len, "doc"); 1.1.1.5 root 1289: #endif 1290: 1.1.1.6 ! root 1291: mask &= files_missing(prefix); 1.1.1.5 root 1292: 1.1.1.6 ! root 1293: prefix[len] = '\0'; ! 1294: return mask; 1.1.1.5 root 1295: } 1296: 1297: /* 1298: * Expands a leading environment variable. Returns 0 on success; 1299: * <0 if there is an error. 1300: */ 1.1.1.6 ! root 1301: static int expand_env(char const *src, char *dest) 1.1.1.5 root 1302: { 1.1.1.6 ! root 1303: char const *var, *suffix; ! 1304: unsigned len; 1.1.1.5 root 1305: 1.1.1.6 ! root 1306: if (*src != '$') { ! 1307: strcpy(dest, src); ! 1308: return 0; ! 1309: } ! 1310: /* Find end of variable */ ! 1311: if (src[1] == '{') { /* ${FOO} form */ ! 1312: var = src + 2; ! 1313: len = strchr(var, '}') - var; ! 1314: suffix = src + 2 + len + 1; ! 1315: } else { /* $FOO form - allow $ for VMS */ ! 1316: var = src + 1; ! 1317: len = strspn(var, "ABCDEFGHIJKLMNOPQRSTUVWXYZ$_"); ! 1318: suffix = src + 1 + len; ! 1319: } ! 1320: ! 1321: memcpy(dest, var, len); /* Copy name */ ! 1322: dest[len] = '\0'; /* Null-terminate */ ! 1323: ! 1324: var = getenv(dest); ! 1325: if (!var || !*var) ! 1326: return -1; /* No env variable */ ! 1327: ! 1328: /* Copy expanded form to destination */ ! 1329: strcpy(dest, var); 1.1.1.5 root 1330: 1.1.1.6 ! root 1331: /* Add tail */ ! 1332: strcat(dest, suffix); 1.1.1.5 root 1333: 1.1.1.6 ! root 1334: return 0; 1.1.1.5 root 1335: } 1336: 1.1.1.6 ! root 1337: /* Don't forget to change 'pgp26' whenever you update rel_version past 2.6 */ ! 1338: char const *const manual_dirs[] = ! 1339: { 1.1.1.5 root 1340: #if defined(VMS) 1.1.1.6 ! root 1341: "$PGPPATH", "", "[pgp]", "[pgp26]", ! 1342: PGP_SYSTEM_DIR, "SYS$LOGIN:", "SYS$LOGIN:[pgp]", ! 1343: "SYS$LOGIN:[pgp26]", "[-]", 1.1.1.5 root 1344: #elif defined(UNIX) 1.1.1.6 ! root 1345: "$PGPPATH", "", "pgp", "pgp26", PGP_SYSTEM_DIR, ! 1346: "$HOME/.pgp", "$HOME", "$HOME/pgp", "$HOME/pgp26", "..", 1.1.1.5 root 1347: #elif defined(AMIGA) 1.1.1.6 ! root 1348: "$PGPPATH", "", "pgp", "pgp26", ":pgp", ":pgp26", ":", "/", ! 1349: #else /* MSDOS or ATARI */ ! 1350: "$PGPPATH", "", "pgp", "pgp26", "\\pgp", "\\pgp26", "\\", "..", ! 1351: "c:\\pgp", "c:\\pgp26", ! 1352: #endif ! 1353: 0}; ! 1354: ! 1355: unsigned manuals_missing(void) ! 1356: { ! 1357: char buf[256]; ! 1358: unsigned mask = ~((unsigned)0); ! 1359: char const *const *p; ! 1360: ! 1361: for (p = manual_dirs; *p; p++) { ! 1362: if (expand_env(*p, buf) < 0) ! 1363: continue; /* Ignore */ ! 1364: mask &= doc_missing(buf); ! 1365: if (!mask) ! 1366: break; ! 1367: } 1.1.1.5 root 1368: 1.1.1.6 ! root 1369: return mask; 1.1.1.5 root 1370: } 1371: 1372: /* 1373: * Why all this code? 1374: * 1375: * Some dimwits have been distributing versions of PGP (especially on MS-DOS) 1376: * without the manuals. This frustrates users (who call Philip Zimmermann 1377: * at all hours of the day and night), and in addition to depriving them 1378: * of instructions on how to operate the program, also deprives them of 1379: * IMPORTANT legal notices. This is a Bad Thing, so we've gone to the 1380: * trouble of being fascist and *forcing* the manuals to be there. 1381: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.