home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / varia / pgp / pgpamiga / source / fileio.c < prev    next >
C/C++ Source or Header  |  1996-11-08  |  36KB  |  1,100 lines

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