|
|
1.1.1.2 ! 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-1992 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: All the source code Philip Zimmermann wrote for PGP is available for ! 10: free under the "Copyleft" General Public License from the Free ! 11: Software Foundation. A copy of that license agreement is included in ! 12: the source release package of PGP. Code developed by others for PGP ! 13: is also freely available. Other code that has been incorporated into ! 14: PGP from other sources was either originally published in the public ! 15: domain or was used with permission from the various authors. See the ! 16: PGP User's Guide for more complete information about licensing, ! 17: patent restrictions on certain algorithms, trademarks, copyrights, ! 18: and export controls. ! 19: ! 20: Modified 16 Apr 92 - HAJK ! 21: Mods for support of VAX/VMS file system ! 22: ! 23: Modified 17 Nov 92 - HAJK ! 24: Change to temp file stuff for VMS. ! 25: */ ! 26: ! 27: #include <ctype.h> ! 28: #include <stdio.h> ! 29: #include <stdlib.h> ! 30: #include <string.h> ! 31: #include <errno.h> ! 32: #ifdef UNIX ! 33: #include <sys/types.h> ! 34: #include <sys/stat.h> ! 35: #include <fcntl.h> ! 36: #if !defined(MACH) && !defined(BSD) ! 37: #include <unistd.h> ! 38: #endif ! 39: #endif /* UNIX */ ! 40: #ifdef VMS ! 41: #include <file.h> ! 42: #endif ! 43: #if (defined(VMS) || defined(UNIX)) && !defined(F_OK) ! 44: #define F_OK 0 ! 45: #define X_OK 1 ! 46: #define W_OK 2 ! 47: #define R_OK 4 ! 48: #endif /* !F_OK */ ! 49: ! 50: #include "random.h" ! 51: #include "mpilib.h" ! 52: #include "mpiio.h" ! 53: #include "fileio.h" ! 54: #include "language.h" ! 55: #include "pgp.h" ! 56: #ifdef MSDOS ! 57: #include <io.h> ! 58: #include <fcntl.h> ! 59: #endif ! 60: ! 61: /* 1st character of temporary file extension */ ! 62: #define TMP_EXT '$' /* extensions are '.$##' */ ! 63: ! 64: /* The PGPPATH environment variable */ ! 65: ! 66: char PGPPATH[] = "PGPPATH"; ! 67: ! 68: /* Disk buffers, used here and in crypto.c */ ! 69: byte textbuf[DISKBUFSIZE]; ! 70: static byte textbuf2[2*DISKBUFSIZE]; ! 71: ! 72: boolean file_exists(char *filename) ! 73: /* Returns TRUE iff file exists. */ ! 74: { ! 75: #if defined(UNIX) || defined(VMS) ! 76: return(access(filename, F_OK) == 0); ! 77: #else ! 78: FILE *f; ! 79: /* open file f for read, in binary (not text) mode...*/ ! 80: if ((f = fopen(filename,FOPRBIN)) == NULL) ! 81: return(FALSE); ! 82: fclose(f); ! 83: return(TRUE); ! 84: #endif ! 85: } /* file_exists */ ! 86: ! 87: ! 88: boolean file_ok_write(char *filename) ! 89: /* Returns TRUE iff file can be opened for writing. ! 90: Does not harm file! ! 91: */ ! 92: { FILE *f; ! 93: if (file_exists (filename)) ! 94: return(TRUE); ! 95: if ((f = fopen(filename,FOPWBIN)) == NULL) ! 96: return(FALSE); ! 97: fclose(f); ! 98: remove(filename); ! 99: return(TRUE); ! 100: } /* file_ok_write */ ! 101: ! 102: boolean is_regular_file(char *filename) ! 103: { ! 104: #ifdef S_ISREG ! 105: struct stat st; ! 106: return(stat(filename, &st) != -1 && S_ISREG(st.st_mode)); ! 107: #else ! 108: return TRUE; ! 109: #endif ! 110: } ! 111: ! 112: int wipeout(FILE *f) ! 113: { /* Completely overwrite and erase file, so that no sensitive ! 114: information is left on the disk. ! 115: NOTE: File MUST be open for read/write. ! 116: */ ! 117: ! 118: long flength; ! 119: int count = 0; ! 120: ! 121: fseek(f, 0L, SEEK_END); ! 122: flength = ftell(f); ! 123: rewind(f); ! 124: ! 125: fill0(textbuf, sizeof(textbuf)); ! 126: while (flength > 0L) ! 127: { /* write zeros to the whole file... */ ! 128: if (flength < (word32) DISKBUFSIZE) ! 129: count = (int)flength; ! 130: else ! 131: count = DISKBUFSIZE; ! 132: fwrite(textbuf,1,count,f); ! 133: flength -= count; ! 134: } ! 135: rewind(f); /* maybe this isn't necessary */ ! 136: return(0); /* normal return */ ! 137: } /* wipeout */ ! 138: ! 139: ! 140: int wipefile(char *filename) ! 141: { /* Completely overwrite and erase file, so that no sensitive ! 142: information is left on the disk. ! 143: */ ! 144: FILE *f; ! 145: /* open file f for read/write, in binary (not text) mode...*/ ! 146: if ((f = fopen(filename,FOPRWBIN)) == NULL) ! 147: return(-1); /* error - file can't be opened */ ! 148: wipeout(f); ! 149: fclose(f); ! 150: return(0); /* normal return */ ! 151: } /* wipefile */ ! 152: ! 153: char *file_tail (char *filename) ! 154: /* Returns the after-slash part of filename. Also skips backslashes, ! 155: * colons, and right brackets. */ ! 156: { ! 157: char *bslashPos = strrchr(filename, '\\');/* Find last bslash in filename */ ! 158: char *slashPos = strrchr(filename, '/');/* Find last slash in filename */ ! 159: char *colonPos = strrchr(filename, ':'); ! 160: char *rbrakPos = strrchr(filename, ']'); ! 161: ! 162: if (!slashPos || bslashPos > slashPos) ! 163: slashPos = bslashPos; ! 164: if (!slashPos || colonPos > slashPos) ! 165: slashPos = colonPos; ! 166: if (!slashPos || rbrakPos > slashPos) ! 167: slashPos = rbrakPos; ! 168: return( slashPos?(slashPos+1):filename ); ! 169: } ! 170: /* Define BSLASH for machines that use backslash, FSLASH for machines ! 171: * that use forward slash as separators. ! 172: */ ! 173: ! 174: #ifdef MSDOS ! 175: #define BSLASH ! 176: #endif ! 177: #ifdef ATARI ! 178: #define BSLASH ! 179: #endif ! 180: #ifdef UNIX ! 181: #define FSLASH ! 182: #define MULTIPLE_DOTS ! 183: #endif ! 184: #ifdef AMIGA ! 185: #define FSLASH ! 186: #define MULTIPLE_DOTS ! 187: #endif ! 188: ! 189: boolean has_extension(char *filename, char *extension) ! 190: { /* return TRUE if extension matches the end of filename */ ! 191: int lf = strlen(filename); ! 192: int lx = strlen(extension); ! 193: ! 194: if (lf <= lx) ! 195: return(FALSE); ! 196: return(!strcmp(filename + lf - lx, extension)); ! 197: } ! 198: ! 199: boolean is_tempfile(char *path) ! 200: { /* return TRUE if path is a filename created by tempfile() */ ! 201: char *p; ! 202: ! 203: return((p = strrchr(path, '.')) != NULL && ! 204: p[1] == TMP_EXT && strlen(p) == 4); ! 205: } ! 206: ! 207: boolean no_extension(char *filename) ! 208: /* Returns TRUE if user left off file extension, allowing default. */ ! 209: { ! 210: #ifdef MULTIPLE_DOTS /* filename can have more than one dot */ ! 211: if (has_extension(filename, CTX_EXTENSION) || ! 212: has_extension(filename, ASC_EXTENSION) || ! 213: has_extension(filename, PGP_EXTENSION) || ! 214: has_extension(filename, SIG_EXTENSION) || ! 215: is_tempfile(filename)) ! 216: return(FALSE); ! 217: else ! 218: return(TRUE); ! 219: #else ! 220: #ifdef BSLASH ! 221: char *slashPos = strrchr(filename, '\\'); /* Find last slash in filename */ ! 222: ! 223: /* Look for the filename after the last slash if there is one */ ! 224: return(strchr((slashPos != NULL ) ? slashPos : filename, '.') == NULL); ! 225: #else ! 226: #ifdef FSLASH ! 227: char *slashPos = strrchr(filename, '/'); /* Find last slash in filename */ ! 228: ! 229: /* Look for the filename after the last slash if there is one */ ! 230: return(strchr((slashPos != NULL ) ? slashPos : filename, '.') == NULL); ! 231: #else ! 232: #ifdef VMS ! 233: char *slashPos = strrchr(filename,']'); /* Locate end of directory spec */ ! 234: ! 235: /* Look for last period in filename */ ! 236: return(strrchr((slashPos != NULL) ? slashPos : filename, '.') == NULL ); ! 237: #else ! 238: return( (strrchr(filename,'.')==NULL) ? TRUE : FALSE ); ! 239: #endif /* VMS */ ! 240: #endif /* FSLASH */ ! 241: #endif /* BSLASH */ ! 242: #endif /* MULTIPLE_DOTS */ ! 243: } /* no_extension */ ! 244: ! 245: ! 246: void drop_extension(char *filename) ! 247: { /* deletes trailing ".xxx" file extension after the period. */ ! 248: if (!no_extension(filename)) ! 249: *strrchr(filename,'.') = '\0'; ! 250: } /* drop_extension */ ! 251: ! 252: ! 253: void default_extension(char *filename, char *extension) ! 254: { /* append filename extension if there isn't one already. */ ! 255: if (no_extension(filename)) ! 256: strcat(filename,extension); ! 257: } /* default_extension */ ! 258: ! 259: #ifndef MAX_NAMELEN ! 260: #if defined(AMIGA) || defined(NeXT) ! 261: #define MAX_NAMELEN 255 ! 262: #endif ! 263: #endif ! 264: ! 265: void truncate_name(char *path, int ext_len) ! 266: { /* truncate the filename so that an extension can be tacked on. */ ! 267: #ifdef UNIX /* for other systems this is a no-op */ ! 268: char dir[MAX_PATH], *p; ! 269: int namemax; ! 270: ! 271: #ifdef MAX_NAMELEN /* overrides the use of pathconf() */ ! 272: namemax = MAX_NAMELEN; ! 273: #else ! 274: #ifdef _PC_NAME_MAX ! 275: strcpy(dir, path); ! 276: if ((p = strrchr(dir, '/')) == NULL) ! 277: strcpy(dir, "."); ! 278: else ! 279: { if (p == dir) ! 280: ++p; ! 281: *p = '\0'; ! 282: } ! 283: if ((namemax = pathconf(dir, _PC_NAME_MAX)) <= ext_len) ! 284: return; ! 285: #else ! 286: namemax = 14; ! 287: #endif ! 288: #endif /* MAX_NAMELEN */ ! 289: ! 290: if ((p = strrchr(path, '/')) == NULL) ! 291: p = path; ! 292: else ! 293: ++p; ! 294: if (strlen(p) > namemax - ext_len) ! 295: { ! 296: if (verbose) ! 297: fprintf(pgpout, "Truncating filename '%s' ", path); ! 298: p[namemax - ext_len] = '\0'; ! 299: if (verbose) ! 300: fprintf(pgpout, "to '%s'\n", path); ! 301: } ! 302: #endif /* UNIX */ ! 303: } ! 304: ! 305: void force_extension(char *filename, char *extension) ! 306: { /* change the filename extension. */ ! 307: drop_extension(filename); /* out with the old */ ! 308: truncate_name(filename, strlen(extension)); ! 309: strcat(filename,extension); /* in with the new */ ! 310: } /* force_extension */ ! 311: ! 312: ! 313: boolean getyesno(char default_answer) ! 314: /* Get yes/no answer from user, returns TRUE for yes, FALSE for no. ! 315: First the translations are checked, if they don't match 'y' and 'n' ! 316: are tried. ! 317: */ ! 318: { char buf[8]; ! 319: static char yes[8], no[8]; ! 320: ! 321: if (yes[0] == '\0') ! 322: { strncpy(yes, PSTR("y"), 7); ! 323: strncpy(no, PSTR("n"), 7); ! 324: } ! 325: flush_input(); ! 326: getstring(buf,6,TRUE); /* echo keyboard input */ ! 327: strlwr(buf); ! 328: if (!strncmp(buf, no, strlen(no))) ! 329: return(FALSE); ! 330: if (!strncmp(buf, yes, strlen(yes))) ! 331: return(TRUE); ! 332: if (buf[0] == 'n') ! 333: return(FALSE); ! 334: if (buf[0] == 'y') ! 335: return(TRUE); ! 336: return(default_answer == 'y' ? TRUE : FALSE); ! 337: } /* getyesno */ ! 338: ! 339: ! 340: ! 341: char *maybe_force_extension(char *filename, char *extension) ! 342: { /* if user consents to it, change the filename extension. */ ! 343: static char newname[MAX_PATH]; ! 344: if (!has_extension(filename,extension)) ! 345: { strcpy(newname,filename); ! 346: force_extension(newname,extension); ! 347: if (!file_exists(newname)) ! 348: { fprintf(pgpout,PSTR("\nShould '%s' be renamed to '%s' [Y/n]? "), ! 349: filename,newname); ! 350: if (getyesno('y')) ! 351: return(newname); ! 352: } ! 353: } ! 354: return(NULL); ! 355: } /* maybe_force_extension */ ! 356: ! 357: char *buildfilename(char *result, char *fname) ! 358: /* Builds a filename with a complete path specifier from the environmental ! 359: variable PGPPATH. ! 360: */ ! 361: { char *s = getenv(PGPPATH); ! 362: ! 363: if ( s==NULL || strlen(s) > 50) /* undefined, or too long to use */ ! 364: s=""; ! 365: strcpy(result,s); ! 366: if (strlen(result) != 0) ! 367: #ifdef BSLASH ! 368: if (result[strlen(result)-1] != '\\') ! 369: strcat(result,"\\"); ! 370: #else ! 371: #ifdef FSLASH ! 372: if (result[strlen(result)-1] != '/') ! 373: strcat(result,"/"); ! 374: #else ! 375: #ifdef VMS ! 376: if (result[strlen(result)-1] != ']') ! 377: strcat(result,"]"); ! 378: #endif ! 379: #endif ! 380: #endif /* Various OS-specific defines */ ! 381: strcat(result,fname); ! 382: return(result); ! 383: } /* buildfilename */ ! 384: ! 385: int build_path(char *path, char *fileName, char *origPath) ! 386: /* Build a path for fileName based on origPath */ ! 387: { int i, lastSlash = 0; ! 388: ! 389: #ifdef BSLASH ! 390: for (i=0; origPath[i]; i++) ! 391: if (origPath[i] == ':' || origPath[i] == '\\') ! 392: lastSlash = i + 1; ! 393: #else ! 394: #ifdef VMS ! 395: for (i=0; origPath[i]; i++) ! 396: if (origPath[i] == ']') ! 397: lastSlash = i + 1; ! 398: #else ! 399: for (i=0; origPath[i]; i++) ! 400: if (origPath[i] == '/') ! 401: lastSlash = i + 1; ! 402: #endif ! 403: #endif ! 404: ! 405: /* Sanity check: Make sure the path is of legal length */ ! 406: if (i>=MAX_PATH) ! 407: { fprintf(pgpout,PSTR("Path '%s' too long\n"), origPath); ! 408: return(-1); /* error return */ ! 409: } ! 410: ! 411: strncpy(path,origPath,lastSlash); /* Add path component */ ! 412: strcpy(path+lastSlash,fileName); /* Append filename */ ! 413: return(0); /* normal return */ ! 414: } /* build_path */ ! 415: ! 416: ! 417: void file_to_canon(char *filename) ! 418: { /* Convert filename to canonical form, with slashes as separators */ ! 419: #ifdef BSLASH ! 420: while (*filename) { ! 421: if (*filename == '\\') ! 422: *filename = '/'; ! 423: ++filename; ! 424: } ! 425: #endif ! 426: } ! 427: ! 428: ! 429: void file_from_canon(char *filename) ! 430: { /* Convert filename from canonical to local form */ ! 431: /* I think everyone can handle slashes */ ! 432: filename = filename; /* Suppress warning */ ! 433: } ! 434: ! 435: ! 436: FILE *fopenbin(char *name, char *mode) ! 437: { ! 438: #if !defined(UNIX) ! 439: char mode_b[8]; ! 440: ! 441: strcpy(mode_b, mode); ! 442: strcat(mode_b, "b"); ! 443: mode = mode_b; ! 444: #endif ! 445: ! 446: #ifdef VMS ! 447: if (*mode == 'r') ! 448: return(fopen(name, mode, "ctx=stm")); ! 449: else ! 450: return(fopen(name, mode)); ! 451: #else ! 452: return(fopen(name, mode)); ! 453: #endif ! 454: } ! 455: ! 456: FILE *fopentxt(char *name, char *mode) ! 457: { ! 458: #ifdef VMS ! 459: if (*mode == 'r') ! 460: return(fopen(name, mode, "ctx=stm")); ! 461: else ! 462: return(fopen(name, mode)); ! 463: #else ! 464: return(fopen(name, mode)); ! 465: #endif ! 466: } ! 467: ! 468: int write_error(FILE *f) ! 469: { ! 470: fflush(f); ! 471: if (ferror(f)) ! 472: { ! 473: #ifdef ENOSPC ! 474: if (errno == ENOSPC) ! 475: fprintf(pgpout, PSTR("\nDisk full.\n")); ! 476: else ! 477: #endif ! 478: fprintf(pgpout, PSTR("\nFile write error.\n")); ! 479: return -1; ! 480: } ! 481: return 0; ! 482: } ! 483: ! 484: int copyfile(FILE *f, FILE *g, word32 longcount) ! 485: { /* copy file f to file g, for longcount bytes */ ! 486: int count, status = 0; ! 487: do /* read and write the whole file... */ ! 488: { ! 489: if (longcount < (word32) DISKBUFSIZE) ! 490: count = (int)longcount; ! 491: else ! 492: count = DISKBUFSIZE; ! 493: count = fread(textbuf,1,count,f); ! 494: if (count>0) ! 495: { ! 496: if (CONVERSION != NO_CONV) ! 497: { int i; ! 498: for (i = 0; i < count; i++) ! 499: textbuf[i] = (CONVERSION == EXT_CONV) ? ! 500: EXT_C(textbuf[i]) : ! 501: INT_C(textbuf[i]); ! 502: } ! 503: if (fwrite(textbuf,1,count,g) != count ) ! 504: { /* Problem: return error value */ ! 505: status = -1; ! 506: break; ! 507: } ! 508: longcount -= count; ! 509: } ! 510: /* if text block was short, exit loop */ ! 511: } while (count==DISKBUFSIZE); ! 512: burn(textbuf); /* burn sensitive data on stack */ ! 513: return(status); ! 514: } /* copyfile */ ! 515: ! 516: int copyfilepos (FILE *f, FILE *g, word32 longcount, word32 fpos) ! 517: /* Like copyfile, but takes a position for file f. Returns with ! 518: * f and g pointing just past the copied data. ! 519: */ ! 520: { ! 521: fseek (f, fpos, SEEK_SET); ! 522: return copyfile (f, g, longcount); ! 523: } ! 524: ! 525: ! 526: int copyfile_to_canon (FILE *f, FILE *g, word32 longcount) ! 527: { /* copy file f to file g, for longcount bytes. Convert to ! 528: canonical form as we go. f is open in text mode. Canonical ! 529: form uses crlf's as line separators. */ ! 530: int count, status = 0; ! 531: byte c, *tb1, *tb2; ! 532: int i, nbytes; ! 533: do /* read and write the whole file... */ ! 534: { ! 535: if (longcount < (word32) DISKBUFSIZE) ! 536: count = (int)longcount; ! 537: else ! 538: count = DISKBUFSIZE; ! 539: count = fread(textbuf,1,count,f); ! 540: if (count>0) ! 541: { /* Convert by adding CR before LF */ ! 542: tb1 = textbuf; ! 543: tb2 = textbuf2; ! 544: for (i=0; i<count; ++i) ! 545: { switch (CONVERSION) { ! 546: case EXT_CONV: ! 547: c = EXT_C(*tb1++); ! 548: break; ! 549: case INT_CONV: ! 550: c = INT_C(*tb1++); ! 551: break; ! 552: default: ! 553: c = *tb1++; ! 554: } ! 555: if (c == '\n') ! 556: *tb2++ = '\r'; ! 557: *tb2++ = c; ! 558: } ! 559: nbytes = tb2 - textbuf2; ! 560: if (fwrite(textbuf2,1,nbytes,g) != nbytes ) ! 561: { /* Problem: return error value */ ! 562: status = -1; ! 563: break; ! 564: } ! 565: longcount -= count; ! 566: } ! 567: /* if text block was short, exit loop */ ! 568: } while (count==DISKBUFSIZE); ! 569: burn(textbuf); /* burn sensitive data on stack */ ! 570: burn(textbuf2); ! 571: return(status); ! 572: } /* copyfile_to_canon */ ! 573: ! 574: ! 575: int copyfile_from_canon (FILE *f, FILE *g, word32 longcount) ! 576: { /* copy file f to file g, for longcount bytes. Convert from ! 577: canonical to local form as we go. g is open in text mode. Canonical ! 578: form uses crlf's as line separators. */ ! 579: int count, status = 0; ! 580: byte c, *tb1, *tb2; ! 581: int i, nbytes; ! 582: do /* read and write the whole file... */ ! 583: { ! 584: if (longcount < (word32) DISKBUFSIZE) ! 585: count = (int)longcount; ! 586: else ! 587: count = DISKBUFSIZE; ! 588: count = fread(textbuf,1,count,f); ! 589: if (count>0) ! 590: { /* Convert by removing CR's */ ! 591: tb1 = textbuf; ! 592: tb2 = textbuf2; ! 593: for (i=0; i<count; ++i) ! 594: { switch (CONVERSION) { ! 595: case EXT_CONV: ! 596: c = EXT_C(*tb1++); ! 597: break; ! 598: case INT_CONV: ! 599: c = INT_C(*tb1++); ! 600: break; ! 601: default: ! 602: c = *tb1++; ! 603: } ! 604: if (c != '\r') ! 605: *tb2++ = c; ! 606: } ! 607: nbytes = tb2 - textbuf2; ! 608: if (fwrite(textbuf2,1,nbytes,g) != nbytes ) ! 609: { /* Problem: return error value */ ! 610: status = -1; ! 611: break; ! 612: } ! 613: longcount -= count; ! 614: } ! 615: /* if text block was short, exit loop */ ! 616: } while (count==DISKBUFSIZE); ! 617: burn(textbuf); /* burn sensitive data on stack */ ! 618: burn(textbuf2); ! 619: return(status); ! 620: } /* copyfile_from_canon */ ! 621: ! 622: ! 623: int copyfiles_by_name(char *srcFile, char *destFile) ! 624: /* Copy srcFile to destFile */ ! 625: { ! 626: FILE *f, *g; ! 627: int status = 0; ! 628: long fileLength; ! 629: ! 630: if (((f=fopen(srcFile,FOPRBIN)) == NULL) || ! 631: ((g=fopen(destFile,FOPWBIN)) == NULL)) ! 632: /* Can't open files */ ! 633: return(-1); ! 634: ! 635: /* Get file length and copy it */ ! 636: fseek(f,0L,SEEK_END); ! 637: fileLength = ftell(f); ! 638: rewind(f); ! 639: status = copyfile(f,g,fileLength); ! 640: fclose(f); ! 641: if (write_error(g)) ! 642: status = -1; ! 643: fclose(g); ! 644: return(status); ! 645: } /* copyfiles_by_name */ ! 646: ! 647: ! 648: int make_canonical(char *srcFile, char *destFile) ! 649: /* Copy srcFile to destFile, converting to canonical text form */ ! 650: { ! 651: FILE *f, *g; ! 652: int status = 0; ! 653: long fileLength; ! 654: ! 655: if (((f=fopen(srcFile,FOPRTXT)) == NULL) || ! 656: ((g=fopen(destFile,FOPWBIN)) == NULL)) ! 657: /* Can't open files */ ! 658: return(-1); ! 659: ! 660: /* Get file length and copy it */ ! 661: fseek(f,0L,SEEK_END); ! 662: fileLength = ftell(f); ! 663: rewind(f); ! 664: CONVERSION = INT_CONV; ! 665: status = copyfile_to_canon(f,g,fileLength); ! 666: CONVERSION = NO_CONV; ! 667: fclose(f); ! 668: if (write_error(g)) ! 669: status = -1; ! 670: fclose(g); ! 671: return(status); ! 672: } /* make_canonical */ ! 673: ! 674: ! 675: int rename2(char *srcFile, char *destFile) ! 676: /* Like rename() but will try to copy the file if the rename fails. ! 677: This is because under OS's with multiple physical volumes if the ! 678: source and destination are on different volumes the rename will fail */ ! 679: { ! 680: FILE *f, *g; ! 681: int status = 0; ! 682: long fileLength; ! 683: ! 684: #ifdef VMS ! 685: if (rename(srcFile,destFile) != 0) ! 686: #else ! 687: if (rename(srcFile,destFile) == -1) ! 688: #endif ! 689: { /* Rename failed, try a copy */ ! 690: if (((f=fopen(srcFile,FOPRBIN)) == NULL) || ! 691: ((g=fopen(destFile,FOPWBIN)) == NULL)) ! 692: /* Can't open files */ ! 693: return(-1); ! 694: ! 695: /* Get file length and copy it */ ! 696: fseek(f,0L,SEEK_END); ! 697: fileLength = ftell(f); ! 698: rewind(f); ! 699: status = copyfile(f,g,fileLength); ! 700: if (write_error(g)) ! 701: status = -1; ! 702: ! 703: /* Zap source file if the copy went OK, otherwise zap the (possibly ! 704: incomplete) destination file */ ! 705: if (status >= 0) ! 706: { wipeout(f); /* Zap source file */ ! 707: fclose(f); ! 708: remove(srcFile); ! 709: fclose(g); ! 710: } ! 711: else ! 712: { if (is_regular_file(destFile)) ! 713: { wipeout(g); /* Zap destination file */ ! 714: fclose(g); ! 715: remove(destFile); ! 716: } else ! 717: fclose(g); ! 718: fclose(f); ! 719: } ! 720: } ! 721: return(status); ! 722: } ! 723: ! 724: ! 725: int readPhantomInput(char *filename) ! 726: /* read the data from stdin to the phantom input file */ ! 727: { FILE *outFilePtr; ! 728: byte buffer[ 512 ]; ! 729: int bytesRead, status = 0; ! 730: ! 731: if (verbose) ! 732: fprintf(pgpout, "writing stdin to file %s\n", filename); ! 733: if ((outFilePtr = fopen(filename,FOPWBIN)) == NULL) ! 734: return(-1); ! 735: ! 736: #ifdef MSDOS ! 737: /* Under DOS must set input stream to binary mode to avoid data mangling */ ! 738: setmode(fileno(stdin), O_BINARY); ! 739: #endif /* MSDOS */ ! 740: while ((bytesRead = fread (buffer, 1, 512, stdin)) > 0) ! 741: if (fwrite (buffer, 1, bytesRead, outFilePtr) != bytesRead) ! 742: { status = -1; ! 743: break; ! 744: } ! 745: if (write_error(outFilePtr)) ! 746: status = -1; ! 747: fclose (outFilePtr); ! 748: #ifdef MSDOS ! 749: setmode(fileno(stdin), O_TEXT); /* Reset stream */ ! 750: #endif /* MSDOS */ ! 751: return(status); ! 752: } ! 753: ! 754: ! 755: int writePhantomOutput(char *filename) ! 756: /* write the data from the phantom output file to stdout */ ! 757: { FILE *outFilePtr; ! 758: byte buffer[ 512 ]; ! 759: int bytesRead, status = 0; ! 760: ! 761: if (verbose) ! 762: fprintf(pgpout, "writing file %s to stdout\n", filename); ! 763: /* this can't fail since we just created the file */ ! 764: outFilePtr = fopen(filename,FOPRBIN); ! 765: ! 766: #ifdef MSDOS ! 767: setmode(fileno(stdout), O_BINARY); ! 768: #endif ! 769: while ((bytesRead = fread (buffer, 1, 512, outFilePtr)) > 0) ! 770: if (fwrite (buffer, 1, bytesRead, stdout) != bytesRead) ! 771: { status = -1; ! 772: break; ! 773: } ! 774: fclose (outFilePtr); ! 775: fflush(stdout); ! 776: if (ferror(stdout)) ! 777: { status = -1; ! 778: fprintf(pgpout, PSTR("\007Write error on stdout.\n")); ! 779: } ! 780: #ifdef MSDOS ! 781: setmode(fileno(stdout), O_TEXT); ! 782: #endif ! 783: ! 784: return(status); ! 785: } ! 786: ! 787: /* Return the size from the current position of file f to the end */ ! 788: word32 fsize (FILE *f) ! 789: { ! 790: long fpos = ftell (f); ! 791: long fpos2; ! 792: ! 793: fseek (f, 0L, SEEK_END); ! 794: fpos2 = ftell (f); ! 795: fseek (f, fpos, SEEK_SET); ! 796: return (word32)(fpos2 - fpos); ! 797: } ! 798: ! 799: /* Return TRUE if file filename looks like a pure text file */ ! 800: int is_text_file (char *filename) ! 801: { ! 802: FILE *f = fopen(filename,"r"); /* FOPRBIN gives problem with VMS */ ! 803: int i, n, bit8 = 0; ! 804: unsigned char buf[512]; ! 805: unsigned char *bufptr = buf; ! 806: unsigned char c; ! 807: ! 808: if (!f) ! 809: return(FALSE); /* error opening it, so not a text file */ ! 810: i = n = fread (buf, 1, sizeof(buf), f); ! 811: fclose(f); ! 812: if (n <= 0) ! 813: return(FALSE); /* empty file or error, not a text file */ ! 814: if (compressSignature(buf) >= 0) ! 815: return(FALSE); ! 816: while (i--) ! 817: { c = *bufptr++; ! 818: if (c & 0x80) ! 819: ++bit8; ! 820: else /* allow BEL BS HT LF VT FF CR EOF control characters */ ! 821: if (c < '\007' || (c > '\r' && c < ' ' && c != '\032')) ! 822: return(FALSE); /* not a text file */ ! 823: } ! 824: if (strcmp(language, "ru")) ! 825: return(TRUE); ! 826: /* assume binary if more than 1/4 bytes have 8th bit set */ ! 827: return(bit8 < n / 4); ! 828: } /* is_text_file */ ! 829: ! 830: VOID *xmalloc(unsigned size) ! 831: { VOID *p; ! 832: if (size == 0) ! 833: ++size; ! 834: if ((p = malloc(size)) == NULL) ! 835: { fprintf(stderr, PSTR("\n\007Out of memory.\n")); ! 836: exitPGP(1); ! 837: } ! 838: return(p); ! 839: } ! 840: ! 841: /*---------------------------------------------------------------------- ! 842: * temporary file routines ! 843: */ ! 844: ! 845: ! 846: #define MAXTMPF 8 ! 847: ! 848: #define TMP_INUSE 2 ! 849: ! 850: static struct ! 851: { char path[MAX_PATH]; ! 852: int flags; ! 853: int num; ! 854: } tmpf[MAXTMPF]; ! 855: ! 856: static char tmpdir[256]; /* temporary file directory */ ! 857: static char outdir[256]; /* output directory */ ! 858: static char tmpbasename[64] = "pgptemp"; /* basename for temporary files */ ! 859: ! 860: ! 861: /* ! 862: * set directory for temporary files. path will be stored in ! 863: * tmpdir[] with an appropriate trailing path separator. ! 864: */ ! 865: void settmpdir(char *path) ! 866: { ! 867: char *p; ! 868: ! 869: if (path == NULL || *path == '\0') ! 870: { tmpdir[0] = '\0'; ! 871: return; ! 872: } ! 873: strcpy(tmpdir, path); ! 874: p = tmpdir + strlen(tmpdir)-1; ! 875: if (*p != '/' && *p != '\\' && *p != ']') ! 876: { /* append path separator, either / or \ */ ! 877: if ((p = strchr(tmpdir, '/')) == NULL && ! 878: (p = strchr(tmpdir, '\\')) == NULL) ! 879: p = "/"; /* path did not contain / or \, use / */ ! 880: strncat(tmpdir, p, 1); ! 881: } ! 882: } ! 883: ! 884: /* ! 885: * set output directory to avoid a file copy when temp file is renamed to ! 886: * output file. the argument filename must be a valid path for a file, not ! 887: * a directory. ! 888: */ ! 889: void setoutdir(char *filename) ! 890: { ! 891: char *p; ! 892: ! 893: if (filename == NULL) ! 894: { strcpy(outdir, tmpdir); ! 895: return; ! 896: } ! 897: strcpy(outdir, filename); ! 898: p = file_tail(outdir); ! 899: strcpy(tmpbasename, p); ! 900: *p = '\0'; ! 901: drop_extension(tmpbasename); ! 902: #if !defined(BSD42) && !defined(BSD43) && !defined(sun) ! 903: /* we don't depend on pathconf here, if it returns an incorrect value ! 904: * for NAME_MAX (like Linux 0.97 with minix FS) finding a unique name ! 905: * for temp files can fail. ! 906: */ ! 907: tmpbasename[10] = '\0'; /* 14 char limit */ ! 908: #endif ! 909: } ! 910: ! 911: /* ! 912: * return a unique temporary file name ! 913: */ ! 914: char *tempfile(int flags) ! 915: { ! 916: int i, j; ! 917: int num; ! 918: int fd; ! 919: #ifndef UNIX ! 920: FILE *fp; ! 921: #endif ! 922: ! 923: for (i = 0; i < MAXTMPF; ++i) ! 924: if (tmpf[i].flags == 0) ! 925: break; ! 926: ! 927: if (i == MAXTMPF) ! 928: { /* message only for debugging, no need for PSTR */ ! 929: fprintf(stderr, "\n\007Out of temporary files\n"); ! 930: return(NULL); ! 931: } ! 932: ! 933: again: ! 934: num = 0; ! 935: do { ! 936: for (j = 0; j < MAXTMPF; ++j) ! 937: if (tmpf[j].flags && tmpf[j].num == num) ! 938: break; ! 939: if (j < MAXTMPF) ! 940: continue; /* sequence number already in use */ ! 941: sprintf(tmpf[i].path, "%s%s.%c%02d", ! 942: ((flags & TMP_TMPDIR) && *tmpdir ? tmpdir : outdir), ! 943: tmpbasename, TMP_EXT, num); ! 944: if (!file_exists(tmpf[i].path)) ! 945: break; ! 946: } ! 947: while (++num < 100); ! 948: ! 949: if (num == 100) ! 950: { fprintf(pgpout, "\n\007tempfile: cannot find unique name\n"); ! 951: return(NULL); ! 952: } ! 953: ! 954: #if defined(UNIX) || defined(VMS) ! 955: if ((fd = open(tmpf[i].path, O_EXCL|O_RDWR|O_CREAT, 0600)) != -1) ! 956: close(fd); ! 957: #else ! 958: if ((fp = fopen(tmpf[i].path, "w")) != NULL) ! 959: fclose(fp); ! 960: fd = (fp == NULL ? -1 : 0); ! 961: #endif ! 962: ! 963: if (fd == -1 && !(flags & TMP_TMPDIR)) ! 964: { ! 965: flags |= TMP_TMPDIR; ! 966: goto again; ! 967: } ! 968: if (fd == -1) ! 969: { fprintf(pgpout, PSTR("\n\007Cannot create temporary file '%s'\n"), tmpf[i].path); ! 970: user_error(); ! 971: } ! 972: #ifdef VMS ! 973: remove(tmpf[i].path); ! 974: #endif ! 975: ! 976: tmpf[i].num = num; ! 977: tmpf[i].flags = flags | TMP_INUSE; ! 978: if (verbose) ! 979: fprintf(pgpout, "tempfile: created '%s'\n", tmpf[i].path); ! 980: return(tmpf[i].path); ! 981: } /* tempfile */ ! 982: ! 983: /* ! 984: * remove temporary file, wipe if necessary. ! 985: */ ! 986: void rmtemp(char *name) ! 987: { ! 988: int i; ! 989: ! 990: for (i = 0; i < MAXTMPF; ++i) ! 991: if (tmpf[i].flags && strcmp(tmpf[i].path, name) == 0) ! 992: break; ! 993: ! 994: if (i < MAXTMPF) ! 995: { if (strlen(name) > 3 && name[strlen(name)-3] == TMP_EXT) ! 996: { /* only remove file if name hasn't changed */ ! 997: if (verbose) ! 998: fprintf(pgpout, "rmtemp: removing '%s'\n", name); ! 999: if (tmpf[i].flags & TMP_WIPE) ! 1000: wipefile(name); ! 1001: if (!remove(name)) { ! 1002: tmpf[i].flags = 0; ! 1003: } else if (verbose) { ! 1004: fprintf(stderr,"\nrmtemp: Failed to remove %s",name); ! 1005: perror ("\nError"); ! 1006: } ! 1007: } else if (verbose) ! 1008: fprintf(pgpout, "rmtemp: not removing '%s'\n", name); ! 1009: } ! 1010: } /* rmtemp */ ! 1011: ! 1012: /* ! 1013: * make temporary file permanent, returns the new name. ! 1014: */ ! 1015: char *savetemp(char *name, char *newname) ! 1016: { ! 1017: int i, overwrite; ! 1018: static char buf[MAX_PATH]; ! 1019: ! 1020: if (strcmp(name, newname) == 0) ! 1021: return(name); ! 1022: ! 1023: for (i = 0; i < MAXTMPF; ++i) ! 1024: if (tmpf[i].flags && strcmp(tmpf[i].path, name) == 0) ! 1025: break; ! 1026: ! 1027: if (i < MAXTMPF) ! 1028: { if (strlen(name) < 4 || name[strlen(name)-3] != TMP_EXT) ! 1029: { if (verbose) ! 1030: fprintf(pgpout, "savetemp: not renaming '%s' to '%s'\n", ! 1031: name, newname); ! 1032: return(name); /* return original file name */ ! 1033: } ! 1034: } ! 1035: ! 1036: while (file_exists(newname)) ! 1037: { ! 1038: if (is_regular_file(newname)) ! 1039: { fprintf(pgpout,PSTR("\n\007Output file '%s' already exists. Overwrite (y/N)? "), ! 1040: newname); ! 1041: overwrite = getyesno('n'); ! 1042: } ! 1043: else ! 1044: { fprintf(pgpout,PSTR("\n\007Output file '%s' already exists.\n"),newname); ! 1045: overwrite = FALSE; ! 1046: } ! 1047: ! 1048: if (!overwrite) ! 1049: { fprintf(pgpout, PSTR("\nEnter new file name: ")); ! 1050: getstring(buf, MAX_PATH - 1, TRUE); ! 1051: if (buf[0] == '\0') ! 1052: return(NULL); ! 1053: newname = buf; ! 1054: } ! 1055: else ! 1056: remove(newname); ! 1057: } ! 1058: if (verbose) ! 1059: fprintf(pgpout, "savetemp: renaming '%s' to '%s'\n", name, newname); ! 1060: if (rename2(name, newname) < 0) ! 1061: { /* errorLvl = UNKNOWN_FILE_ERROR; */ ! 1062: fprintf(pgpout, PSTR("Can't create output file '%s'\n"), newname); ! 1063: return(NULL); ! 1064: } ! 1065: if (i < MAXTMPF) ! 1066: tmpf[i].flags = 0; ! 1067: return(newname); ! 1068: } /* savetemp */ ! 1069: ! 1070: /* ! 1071: * like savetemp(), only make backup of destname if it exists ! 1072: */ ! 1073: int savetempbak(char *tmpname, char *destname) ! 1074: { ! 1075: char bakpath[MAX_PATH]; ! 1076: int mode = -1; ! 1077: ! 1078: if (is_tempfile(destname)) ! 1079: remove(destname); ! 1080: else ! 1081: { if (file_exists(destname)) ! 1082: { ! 1083: #ifdef UNIX ! 1084: struct stat st; ! 1085: if (stat(destname, &st) != -1) ! 1086: mode = st.st_mode & 07777; ! 1087: #endif ! 1088: strcpy(bakpath, destname); ! 1089: force_extension(bakpath, BAK_EXTENSION); ! 1090: remove(bakpath); ! 1091: #ifdef VMS ! 1092: if (rename(destname, bakpath) != 0) ! 1093: #else ! 1094: if (rename(destname, bakpath) == -1) ! 1095: #endif ! 1096: return(-1); ! 1097: } ! 1098: } ! 1099: if (savetemp(tmpname, destname) == NULL) ! 1100: return(-1); ! 1101: #ifdef UNIX ! 1102: if (mode != -1) ! 1103: chmod(destname, mode); ! 1104: #endif ! 1105: return(0); ! 1106: } ! 1107: ! 1108: /* ! 1109: * remove all temporary files and wipe them if necessary ! 1110: */ ! 1111: void cleanup_tmpf(void) ! 1112: { ! 1113: int i; ! 1114: ! 1115: for (i = 0; i < MAXTMPF; ++i) ! 1116: if (tmpf[i].flags) ! 1117: rmtemp(tmpf[i].path); ! 1118: } /* cleanup_tmpf */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.