"Fossies" - the Fresh Open Source Software Archive

Member "tofrodos/src/tofrodos.c" (27 Oct 2013, 21310 Bytes) of archive /linux/misc/tofrodos-1.7.13.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "tofrodos.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2     tofrodos.c  Converts text files between DOS and Unix formats.
    3     Copyright 1996-2013 Christopher Heng. All rights reserved.
    4 */
    5 
    6 /* this should always be first */
    7 #include "config.h"
    8 
    9 /* standard headers */
   10 #include <errno.h>  /* errno */
   11 #include <signal.h> /* signal() */
   12 #include <stdio.h>  /* FILE functions */
   13 #include <stdlib.h> /* EXIT_SUCCESS, mkstemp() in some systems, ltoa() */
   14 #include <string.h> /* strrchr(), strlen(), strcpy(), strcat(), strerror() */
   15 #include <sys/stat.h>   /* stat() */
   16 
   17 #if defined(_MSC_VER) || defined(__WATCOMC__)
   18 #include <sys/utime.h>
   19 #else   /* everybody else keeps this in the include directory */
   20 #if defined(UNIX)
   21 #include <sys/types.h>
   22 #endif
   23 #include <utime.h>
   24 #endif
   25 
   26 /* conditionally included headers */
   27 #if defined(MSDOS) || defined(WIN32)
   28 #include <fcntl.h>  /* O_BINARY */
   29 #include <io.h>     /* chmod(), setmode(), isatty() */
   30 #endif
   31 
   32 #if defined(HAVE_GETOPT_H)
   33 #include <getopt.h> /* optind, getopt() */
   34 #endif
   35 
   36 #if defined(HAVE_MKTEMP_H) && defined(MKTEMP_HEADER)
   37 #include MKTEMP_HEADER
   38 #endif
   39 
   40 #if defined(HAVE_UNISTD_H)
   41 #include <unistd.h> /* chmod(), mktemp(), isatty(), chown(), readlink(), mkstemp() in some systems, (getopt()) */
   42 #endif
   43 
   44 /* our headers */
   45 #include "emsg.h"
   46 #include "tofrodos.h"
   47 #include "utility.h"
   48 #include "version.h"
   49 
   50 /* macros */
   51 #define BAKEXT      ".bak"  /* backup file extension */
   52 #define MKTEMP_TEMPL    "XXXXXX"
   53 #define NEWBUFSIZ   16384   /* buffer size for the files */
   54 
   55 #if defined(MSDOS) || defined(WIN32)
   56 #define DIRSLASH    '\\'
   57 #define DIRSLASHSTR "\\"
   58 #else
   59 #define DIRSLASH    '/'
   60 #define DIRSLASHSTR "/"
   61 #endif
   62 
   63 /* conditional macros */
   64 #if defined(MSDOS)
   65 #if !defined(_MAX_DIR) || (_MAX_DIR < 260)  /* MAXDIRSIZE */
   66 #define MAXDIRSIZE  260
   67 #else
   68 #define MAXDIRSIZE  _MAX_DIR
   69 #endif
   70 #if !defined(_MAX_NAME) || (_MAX_NAME < 260)    /* MAXFILESIZE */
   71 #define MAXFILESIZE 260
   72 #else
   73 #define MAXFILESIZE _MAX_NAME
   74 #endif
   75 #if !defined(_MAX_PATH) || (_MAX_PATH < 260)    /* MAXPATHSIZE */
   76 #define MAXPATHSIZE 260
   77 #else
   78 #define MAXPATHSIZE _MAX_PATH
   79 #endif
   80 #if !defined(_MAX_DRIVE)
   81 #define _MAX_DRIVE  3       /* for the benefit of djgpp */
   82 #endif
   83 #endif  /* if defined(MSDOS) */
   84 
   85 #if defined(MSDOS) || defined(WIN32)
   86 #define INFILEMODE  "rb"
   87 #define OUTFILEMODE "wb"
   88 #else
   89 #define INFILEMODE  "r"
   90 #define OUTFILEMODE "w"
   91 #endif
   92 
   93 #if defined(MSDOS) || defined(WIN32)
   94 #define CURRENTDIR  ".\\"   /* not used in MSDOS though */
   95 #else   /* Unix-type systems */
   96 #define CURRENTDIR  "./"
   97 #endif
   98 
   99 
  100 /* global variables */
  101 int abortonerr ;    /* 1 if should abort when there is error in any file */
  102                     /* in a list of files, 0 carry on (default) */
  103 int alwaysconvert ; /* convert all \r\n to \r\r\n when direction */
  104                     /* is UNIXTODOS, and delete all \r when direction is */
  105                     /* DOSTOUNIX */
  106 int direction = DEFDIRECTION ; /* UNIXTODOS or DOSTOUNIX */
  107 int forcewrite ; /* convert even if file is not writeable */
  108 char * errorlogfilename ;   /* name of error log file, NULL if we're printing to stderr */
  109 int preserve ;  /* 1 if we are to preserve owner (Unix) and date (all) */
  110 char * progname = VERSN_PROGNAME ;/* name of binary (ie, argv[0]) */
  111 int overwrite = 1 ; /* 1 = overwrite original file, 0 = make backup */
  112 int verbose ;
  113 
  114 /* local variables */
  115 static char * infilename = "stdin" ;
  116 static FILE * tempfp ;
  117 static char * tempfilename ;
  118 
  119 /* local functions */
  120 #if !defined(UNIX)
  121 static int checkmode ( char * filename, unsigned short * origfilemodep,
  122     struct utimbuf * filetimebufp );
  123 #else
  124 static int checkmode ( char * filename, unsigned short * origfilemodep,
  125     struct utimbuf * filetimebufp, uid_t * ownerp, gid_t * groupp );
  126 #endif
  127 static int convert ( FILE * infp, FILE * outfp );
  128 static int openandconvert ( char * filename );
  129 #if !defined(UNIX)
  130 #define openandconvert_preamble openandconvert
  131 #else
  132 static int openandconvert_preamble ( char * filename );
  133 #endif
  134 
  135 /*
  136     main
  137 
  138     tofrodos converts ASCII text files to/from a DOS CR-LF deliminated
  139     form from/to a Unix LF deliminated form.
  140 
  141     Usage: tofrodos [options] [file...]
  142 
  143     Exit codes:
  144         EXIT_SUCCESS    success (stdlib.h)
  145         EXIT_ERROR  error   (tofrodos.h)
  146 */
  147 int main ( int argc, char ** argv )
  148 {
  149     int err ;
  150 
  151     /* initialise and parse the options */
  152     if (init( argv[0] ) || parseargs( argc, argv ))
  153         return EXIT_ERROR ;
  154 
  155     /* check if we are to convert from stdin */
  156     if (argc == optind) {
  157         if (isatty( fileno( stdin ) )) {
  158         /* stdin must be redirected else you should supply a */
  159         /* filename. */
  160         emsg( EMSG_NOFILENAME );
  161         return EXIT_ERROR ;
  162         }
  163         /* otherwise stdin has been redirected */
  164 #if defined(MSDOS) || defined(WIN32)
  165         /* need to make sure the input and output files are binary */
  166         /* on MSDOS and WIN32 */
  167         setmode( fileno( stdin ), O_BINARY );
  168         setmode( fileno( stdout ), O_BINARY );
  169 #endif
  170         return openandconvert( NULL ) ? EXIT_ERROR : EXIT_SUCCESS ;
  171     }
  172 
  173     /* if we reach here, we have a (list?) of files to convert */
  174     /* (ignore stdin) */
  175     err = 0 ;
  176     while (optind < argc) {
  177         if (verbose)
  178             emsg( VERBOSE_CONVERTING, argv[optind] );
  179         if ((err = openandconvert_preamble( argv[optind] )) != 0 && abortonerr)
  180             return EXIT_ERROR ;
  181         optind++ ;
  182     }
  183 
  184     return err ? EXIT_ERROR : EXIT_SUCCESS ;
  185 }
  186 
  187 /*
  188     sighandler
  189 
  190     Handles SIGINT and SIGTERM. Prints a message, closes and
  191     deletes the temporary files and quits with EXIT_ERROR.
  192 
  193         It never returns (and Watcom C knows it).
  194 */
  195 void sighandler ( int sig )
  196 {
  197     /* restore signal handler, in case we have the old unsafe behaviour */
  198     signal( sig, sighandler );
  199 
  200     /* print error message for this only if verbose */
  201     if (verbose)
  202         emsg( EMSG_SIGNAL );
  203 
  204     /* close the temporary file and delete it */
  205     if (tempfp != NULL) {
  206         fclose( tempfp );
  207         tempfp = NULL ;
  208     }
  209     if (tempfilename != NULL) {
  210         remove( tempfilename );
  211         tempfilename = NULL ;
  212     }
  213 
  214     exit( EXIT_ERROR );
  215 }
  216 
  217 /* ---------------------------- local functions --------------------- */
  218 /*
  219     checkmode
  220 
  221     Checks that the file we are supposed to convert is indeed
  222     writeable. We don't really need for it to be writeable, since
  223     we actually open a new file and eventually delete the current
  224     file.
  225 
  226     However, if a file is marked not-writeable, we should at least
  227     respect the user's choice and abort unless he flags the
  228     forcewrite flag.
  229 
  230     At the same time we also save the current mode of the file
  231     so that we can set the converted file to the same mode. The
  232     value is saved in the variable pointed to by origfilemodep.
  233 
  234     Returns: 0 on success, -1 on error.
  235 
  236     If -1 is returned, it could mean one of few things:
  237     1) some component of the path was not valid (directory or the file
  238     itself) (DOS/Unix) or search permission was denied (Unix)
  239     2) the file is not readable
  240     3) the file is not writeable and forcewrite is zero.
  241     An error message is displayed on error.
  242 */
  243 #if !defined(UNIX)
  244 static int checkmode ( char * filename, unsigned short * origfilemodep,
  245     struct utimbuf * filetimebufp )
  246 #else
  247 static int checkmode ( char * filename, unsigned short * origfilemodep,
  248     struct utimbuf * filetimebufp, uid_t * ownerp, gid_t * groupp )
  249 #endif
  250 {
  251     struct stat statbuf ;
  252 
  253     /* get the file information */
  254     if (stat( filename, &statbuf )) {
  255         /* couldn't stat the file. */
  256         emsg( EMSG_ACCESSFILE, filename );
  257         return -1 ;
  258     }
  259     /* save the mode */
  260     *origfilemodep = statbuf.st_mode ;
  261     /* save the file times for restore later */
  262     filetimebufp->actime = statbuf.st_atime ;
  263     filetimebufp->modtime = statbuf.st_mtime ;
  264 #if defined(UNIX)
  265     /* save the owner and group id */
  266     *ownerp = statbuf.st_uid ;
  267     *groupp = statbuf.st_gid ;
  268 #endif
  269     /* check if file can be read - this is actually redundant for */
  270     /* DOS systems. */
  271     if (!(statbuf.st_mode & S_IRUSR)) { /* not readable */
  272         emsg( EMSG_NOTREADABLE, filename );
  273         return -1 ;
  274     }
  275     /* check if file can be written to, if forcewrite is 0 */
  276     if (!forcewrite && !(statbuf.st_mode & S_IWUSR)) { /* not writeable */
  277         emsg( EMSG_NOTWRITEABLE, filename );
  278         return -1 ;
  279     }
  280     return 0 ;
  281 }
  282 
  283 /*
  284     convert
  285 
  286     Does the actual work of converting infp to outfp.
  287 
  288     If direction is DOSTOUNIX, "\r\n" pairs will be converted to
  289     '\n'. However, standalone '\r' without a '\n' immediately
  290     following will not be eliminated unless alwaysconvert is
  291     nonzero.
  292 
  293     If direction is UNIXTODOS, '\n' will be converted to "\r\n".
  294     However "\r\n" pairs are not converted to '\r\r\n' unless
  295     alwaysconvert is nonzero.
  296 
  297         Returns 0 on success, -1 on error.
  298 */
  299 static int convert ( FILE * infp, FILE * outfp )
  300 {
  301     int prevch ;
  302     int c ;
  303 
  304     /* actually it is very simple to do the conversion in DOS/WIN32 */
  305     /* because the stdio library does this work automatically for */
  306     /* us. But since we want this program to work on Linux as */
  307     /* well, a little bit of work stands before us (but only a little). */
  308 
  309     prevch = EOF ;
  310 
  311     if (direction == UNIXTODOS) {
  312         /* basically we convert all newlines to "\r\n" unless */
  313         /* the file is already in "\r\n" format. The problem here */
  314         /* is when you have special situations like a Unix */
  315         /* text file with lines that have a '\r' just */
  316         /* before a '\n'. These lines will */
  317         /* not be converted to "\r\r\n" since the function */
  318         /* below assumes the line has already been converted. */
  319         /* To force the conversion of all \n to \r\n regardless */
  320         /* of preceding characters, set alwaysconvert to 1. */
  321         while ( (c = getc( infp )) != EOF ) {
  322             if (c == '\n' && (alwaysconvert || prevch != '\r')) {
  323                 if (putc( '\r', outfp ) == EOF)
  324                     break ;
  325             }
  326             /* always emit the current character */
  327             if (putc( c, outfp ) == EOF)
  328                 break ;
  329             prevch = c ;                             
  330         }
  331     }
  332     else if (direction == DOSTOUNIX) {
  333         if (!alwaysconvert) {
  334             /* basically we withhold emitting any '\r' until we */
  335             /* are sure that the next character is not a '\n'. */
  336             /* If it is not, we emit the '\r', if it is, we */
  337             /* only emit the '\n'. */
  338             while ( (c = getc( infp )) != EOF ) {
  339                 if (prevch == '\r') {
  340                     /* '\r' is a special case because we don't */
  341                     /* emit a '\r' until the next character */
  342                     /* has been read */
  343                     if (c == '\n') { /* a "\r\n" pair */
  344                         /* discard previous '\r' and */
  345                         /* just put the '\n' */
  346                         if (putc( c, outfp ) == EOF)
  347                             break ;
  348                     }
  349                     else {  /* prevch was a standalone '\r' but the current char is not '\n' */
  350                             /* emit the standalone '\r' */
  351                         if (putc( '\r', outfp ) == EOF)
  352                             break ;
  353                         /* emit the current character if */
  354                         /* it is not a '\r' */
  355                         if (c != '\r') {
  356                             if (putc( c, outfp ) == EOF)
  357                                 break ;
  358                         }
  359                     }
  360                 }
  361                 else { /* prevch was not '\r' */
  362                     /* emit current character if it is not */
  363                     /* a '\r' */
  364                     if (c != '\r') {
  365                         if (putc( c, outfp ) == EOF)
  366                             break ;
  367                     }
  368                 }
  369                 prevch = c ;
  370             }
  371         }   /* alwaysconvert == 0 */
  372         else { /* eliminate all '\r' */
  373             while ((c = getc( infp )) != EOF) {
  374                 if (c != '\r') {
  375                     if (putc( c, outfp ) == EOF)
  376                         break ;
  377                 }
  378                 /* else skip all carriage returns */
  379             }
  380         }
  381     }
  382     else {
  383         emsg( EMSG_INTERNAL, EINTNL_DIRECTION );
  384         return -1 ;
  385     }
  386 
  387     /* if we reach here, either we've reached an EOF or an error */
  388     /* occurred. */
  389     if (!feof( infp )) { /* error */
  390         emsg( EMSG_CONVERT, infilename );
  391         return -1 ;
  392     }
  393     return 0 ;
  394 }
  395 
  396 #if defined(UNIX)
  397 /*
  398     openandconvert_preamble
  399 
  400     On a Unix-type system (including Linux and BSD systems), it is
  401     possible for a given filename to be merely a symlink. This function
  402     obtains the real filename given the symlink, and calls
  403     openandconvert() with the real file name. It simply calls openandconvert()
  404     if the filename is not a symlink.
  405 
  406     Note: this function only exists on Unix-type systems. On MSDOS and Windows,
  407     openandconvert_preamble() is merely a macro that resolves to
  408     openandconvert().
  409 
  410     Returns: whatever openandconvert() returns. (0 on success, -1 on
  411     error. Error messages will be displayed on error before returning.
  412 */
  413 static int openandconvert_preamble ( char * filename )
  414 {
  415     struct stat statbuf ;
  416     char *      realfilepath ;
  417     int         len ;
  418     int         err ;
  419 
  420     /* get the file information */
  421     if (lstat( filename, &statbuf )) {
  422         /* couldn't stat the file. */
  423         emsg( EMSG_ACCESSFILE, filename );
  424         return -1 ;
  425     }
  426 
  427     if (S_ISLNK(statbuf.st_mode)) {
  428         /* get the real filename for symbolic links */
  429         /* Note: the S_ISLNK() macro is supposed to exist in sys/stat.h */
  430         /* Early Unices may not have this macro. If it does not exist, you */
  431         /* may have to define it yourself, a la S_ISDIR() and family. */
  432         /* eg, #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) */
  433         /* or something like that. */
  434 
  435         /* for symbolic links, st_size contains the length of the pathname sans terminating null byte */
  436         if (statbuf.st_size == 0) {
  437             /* There's a report somewhere of a discovery that Mac OS X returns st_size == 0 for "/dev/stdin" when it
  438             is a symlink to "fd/0". I'm not sure if it is a valid report, but let's play it safe. */
  439             emsg ( EMSG_SYMLINK, filename );
  440             return -1 ;
  441         }
  442         realfilepath = xmalloc( statbuf.st_size + 1 );
  443 
  444         if ((len = readlink( filename, realfilepath, statbuf.st_size )) != -1) {
  445 
  446             /* got to null terminate the string - there is always space because */
  447             /* we passed readlink() the size of the buffer less 1. */
  448             realfilepath[len] = '\0' ;
  449             if (verbose) {
  450                 emsg( VERBOSE_SYMLINKSRC, filename, realfilepath );
  451             }
  452             err = openandconvert( realfilepath );
  453         }
  454         else {
  455             emsg( EMSG_SYMLINK, filename );
  456             err = -1 ;
  457         }
  458         free ( realfilepath );
  459         return err ;
  460     }
  461     /* If we reach here, "filename" is not a symbolic link */
  462     return openandconvert( filename );
  463 }
  464 #endif
  465 
  466 
  467 /*
  468     openandconvert
  469 
  470     Called to open the files and convert the contents. If you want
  471     it to convert stdin to stdout, call it with NULL as the filename
  472     argument; otherwise pass the function the name of the input file.
  473 
  474     Returns: 0 on success, -1 on error. Error messages will be
  475         displayed on error before returning.
  476 */
  477 static int openandconvert ( char * filename )
  478 {
  479     FILE *          infp ;
  480     FILE *          outfp ;
  481     int             err ;
  482     char *          bakfilename ;
  483     unsigned short  origfilemode ;  /* file mode of original file */
  484     struct utimbuf  filetimebuf ;
  485     int             tempfiledes;
  486 #if defined(MSDOS)
  487     char            drv[_MAX_DRIVE];
  488     char            dir[MAXDIRSIZE];
  489     char            fname[MAXFILESIZE];
  490     char            tempname[MAXPATHSIZE];
  491 #else
  492     char *          s ;
  493     char *          t ;
  494     size_t          len ;
  495     int             replacech ;
  496     char            c ;
  497 #endif
  498 #if defined(UNIX)
  499     uid_t           ownerid ;
  500     gid_t           groupid ;
  501 #endif
  502 #if NEWBUFSIZ > BUFSIZ
  503     char *          inbufptr ;
  504     char *          outbufptr ;
  505 #endif
  506 
  507     /* make sure we initialise */
  508     bakfilename = NULL ;
  509     err = 0 ;
  510 
  511     if (filename != NULL) { /* stdin is not redirected */
  512 
  513         /* check for appropriate permissions on the file */
  514         /* also saves the mode in origfilemode */
  515 #if !defined(UNIX) 
  516         if (checkmode( filename, &origfilemode, &filetimebuf ))
  517             return -1 ;
  518 #else
  519         if (checkmode( filename, &origfilemode, &filetimebuf,
  520             &ownerid, &groupid ))
  521             return -1 ;
  522 #endif
  523 
  524         /* we need to create a temporary and backup filename (if */
  525         /* applicable) in the same directory */
  526         /* as our file. This is easy to do for DOS since we have the */
  527         /* _splitpath(), _makepath() functions. */
  528 #if defined(MSDOS)
  529         _splitpath( filename, drv, dir, fname, NULL );
  530         _makepath( tempname, drv, dir, MKTEMP_TEMPL, NULL );
  531         tempfilename = xstrdup( tempname );
  532         if (!overwrite) {
  533             _makepath( tempname, drv, dir, fname, BAKEXT );
  534             if (!strcmp( tempname, filename )) {
  535                 emsg( EMSG_BAKFILENAME, filename );
  536                 err = -1 ;
  537                 goto err_freetempfn ;
  538             }
  539             bakfilename = xstrdup( tempname );
  540         }
  541 #else   /* not MSDOS - ie, Linux, Windows, anything else */
  542         /* check if there is a path prefix */
  543         if ((s = strrchr( filename, DIRSLASH )) != NULL) {
  544             c = *++s ;  /* save the character after the slash */
  545             *s = '\0';
  546             replacech = 1 ;
  547             len = strlen( filename ) ;
  548             t = filename ;
  549         }
  550         else {
  551             replacech = c = 0 ; /* c is initialized as well to suppress */
  552                                 /* the warning issued by gcc -Wall */
  553             len = sizeof(CURRENTDIR) - 1 ;
  554             t = CURRENTDIR ;
  555         }
  556         tempfilename = xmalloc( len + sizeof(MKTEMP_TEMPL) );
  557         strcpy( tempfilename, t ); /* add the path leading to filename */
  558         strcat( tempfilename, MKTEMP_TEMPL ); /* add the filename */
  559         if (replacech)
  560             *s = c ;
  561         if (!overwrite) {
  562             bakfilename = xmalloc( strlen( filename ) + sizeof( BAKEXT ) );
  563             strcpy( bakfilename, filename );
  564             strcat( bakfilename, BAKEXT );  /* append the extension to existing filename to create name of backup file */
  565         }
  566 #endif
  567 
  568         /* create the temporary file */
  569         if ((tempfiledes = mkstemp( tempfilename )) == -1) {
  570             emsg( EMSG_NOTEMPNAME, filename );
  571             err = -1 ;  /* redundant; defensive */
  572 err_freebakfn:
  573             if (!overwrite && bakfilename != NULL)
  574                 free( bakfilename );
  575 #if defined(MSDOS)
  576 err_freetempfn:
  577 #endif
  578             free( tempfilename );
  579             tempfilename = NULL ;
  580             return -1 ;
  581         }
  582 
  583         /* open the filename as the input file */
  584         if ((infp = fopen( filename, INFILEMODE )) == NULL) {
  585             emsg( EMSG_OPENFILE, filename );
  586             err = -1 ;
  587             goto err_freebakfn ;
  588         }
  589         /* associate the infilename with the filename for error */
  590         /* messages */
  591         infilename = filename ;
  592 
  593         /* open the temp file as the output file */
  594         if ((tempfp = fdopen( tempfiledes, OUTFILEMODE )) == NULL) {
  595             close ( tempfiledes );
  596             remove ( tempfilename );
  597             emsg( EMSG_CREATETEMP, tempfilename, filename );
  598             fclose( infp );
  599             err = -1 ;
  600             goto err_freebakfn ;
  601         }
  602         outfp = tempfp ;
  603 
  604     } /* if filename != NULL */
  605     else { /* filename == NULL, ie stdin is redirected */
  606         infp = stdin ;
  607         outfp = stdout ;
  608 
  609         /* not needed, but we do this for the record, and for */
  610         /* fussy compilers */
  611         origfilemode    = 0 ;
  612         memset( &filetimebuf, 0, sizeof( struct utimbuf ) );
  613 
  614 #if defined(UNIX)
  615         ownerid = groupid   = 0 ;
  616 #endif
  617 
  618     }
  619 
  620 #if NEWBUFSIZ > BUFSIZ
  621     /* (don't use xmalloc() because if we can't get what we want, */
  622     /* we just don't bother, and go ahead with the minimum) */
  623     if ((inbufptr = malloc( NEWBUFSIZ )) != NULL)
  624         setvbuf( infp, inbufptr, _IOFBF, NEWBUFSIZ );
  625     if ((outbufptr = malloc( NEWBUFSIZ )) != NULL)
  626         setvbuf( outfp, outbufptr, _IOFBF, NEWBUFSIZ );
  627 #endif
  628     /* do the conversion */
  629     err = convert( infp, outfp );
  630 
  631     /* close the files */
  632     fclose( infp );
  633     fclose( outfp );
  634 
  635     if (tempfp != NULL) {
  636         /* remove the output file handle from the global to avoid */
  637         /* double attempts to close the same file */
  638         tempfp = NULL ;
  639     }
  640 
  641 #if NEWBUFSIZ > BUFSIZ
  642     /* got to free buffers we allocated first */
  643     if (inbufptr != NULL)
  644         free( inbufptr );
  645     if (outbufptr != NULL)
  646         free( outbufptr );
  647 #endif
  648 
  649     if (filename != NULL) { /* stdin was not redirected */
  650 
  651         if (err) { /* there was an error */
  652             /* delete the temp file since we've already created it */
  653             remove ( tempfilename );
  654             goto err_freebakfn ;
  655         }
  656 
  657         if (!overwrite) {
  658 #if defined(MSDOS) || defined(WIN32)
  659             /* delete any backup file of the same name first, since a rename() does not delete it automatically */
  660             /* on DOS and Windows */
  661             chmod( bakfilename, S_IRUSR|S_IWUSR );  /* make it writeable (in case it's not) so that it can be deleted */
  662             remove( bakfilename );  /* don't check for error returns since the file may not even exist in the first place */
  663 #endif
  664             /* rename the original file to the back up name */
  665             if (rename( filename, bakfilename )) {
  666                 emsg( EMSG_RENAMEBAK, filename, bakfilename, strerror( errno ) );
  667             }
  668         }
  669 #if defined(MSDOS) || defined(WIN32)    /* we need to delete the original file because a rename() operation will not */
  670                                         /* automatically delete it for us on DOS and Windows the way it does on POSIX systems */
  671         else { /* if we do not need to back up the original file */
  672             chmod( filename, S_IRUSR|S_IWUSR ); /* make it writeable (in case it's not) so that it can be deleted. */
  673             remove( filename ); /* delete the original file */
  674             /* we don't check for error returns for this, since any error message about its failure will just */
  675             /* confuse the user. "What? Why is it deleting my file?" If this fails, the next rename() will fail too */
  676             /* since rename() on Windows will not delete the target automatically, and the error message will from the */
  677             /* failed rename() will tell the user what happened. */
  678         }
  679 #endif
  680 
  681         /* rename the temp file to the original file name */
  682         if (rename( tempfilename, filename )) {
  683             emsg( EMSG_RENAMETMP, tempfilename, filename, strerror( errno ) );
  684         }
  685 
  686         /* remove the temp file name from the global for our */
  687         /* signal handler*/
  688         tempfilename = NULL ;
  689 
  690         /* free memory we allocated */
  691         if (!overwrite && bakfilename != NULL)
  692             free( bakfilename );
  693 
  694         if (preserve) {
  695             /* change to the original file time */
  696             utime( filename, &filetimebuf );
  697 #if defined(UNIX)
  698             /* Change the owner to the owner of the original file. */
  699             /* We ignore errors since the user might simply want */
  700             /* to use -p to set the file time, and not being root, */
  701             /* chown() will fail on Linux. However, we issue an error */
  702             /* message if the user wants verbosity. */
  703             if (chown( filename, ownerid, groupid ) && verbose)
  704                 emsg( EMSG_CHOWN, filename );
  705 #endif
  706         }
  707 
  708         /* change the file mode to reflect the original file mode */
  709         chmod( filename, origfilemode );
  710 
  711     }   /* stdin was not redirected */
  712 
  713     return err ;
  714 }