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