|
|
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.