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