/************************************************************************************************** $Header: /pub/cvsroot/yencode/src/output.c,v 1.11 2002/03/10 16:25:52 bboy Exp $ Copyright (C) 2002 Don Moore This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at Your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA **************************************************************************************************/ #include "y.h" extern int opt_keep_paths; /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ USERMSG Simple routine to standardize output for decoding errors. +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ void usermsg( const char *output_filename, const char *input_filename, int input_part_number, int total_part_number, char *error_message, const char *fmt, ... ) { va_list ap; char msg[BUFSIZ]; if (fmt) { va_start(ap, fmt); vsnprintf(msg, sizeof(msg), fmt, ap); va_end(ap); } else *msg = '\0'; if (output_filename) fprintf(stderr, "%s: ", output_filename); if (input_filename) fprintf(stderr, "%s%s", input_filename, input_part_number ? " " : ": "); if (input_part_number) { if (total_part_number) fprintf(stderr, "(%d/%d): ", input_part_number, total_part_number); else fprintf(stderr, "(%d): ", input_part_number); } if (error_message) fprintf(stderr, "%s%s", error_message, *msg ? ": " : ""); if (*msg) fprintf(stderr, "%s", msg); fputc('\n', stderr); } /*--- decerr() ----------------------------------------------------------------------------------*/ /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ COPY_FILE_PERMS Copies owner, group, and permissions from 'src' to 'dest'. Returns 0 on success, -1 on error. +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ static int copy_file_perms(const char *srcfile, const char *destfile) { struct stat src, dest; if (stat(srcfile, &src)) return WarnERR("%s", srcfile); if (stat(destfile, &dest)) return WarnERR("%s", destfile); if (chown(destfile, src.st_uid, src.st_gid)) return WarnERR("%s", destfile); return (chmod(destfile, src.st_mode)); } /*--- copy_file_perms() -------------------------------------------------------------------------*/ /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ CREATE_PATHS Creates paths for an output file. +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ static void create_paths(const char *filename) { char name[PATH_MAX], path[PATH_MAX]; char *c, *ns; struct stat st; strncpy(name, filename, sizeof(name)-1); /* Find last component (filename) and remove it, leaving the path part of the filename */ if (!(c = strrchr(name, '/'))) return; *c = '\0'; /* Traverse through paths, creating dirs */ *path = '\0'; ns = name; while ((c = strsep(&ns, "/"))) { strncat(path, c, sizeof(path)-strlen(path)-1); strncat(path, "/", sizeof(path)-strlen(path)-1); if (stat(path, &st)) { if (errno != ENOENT) ErrERR("%s", path); if (mkdir(path, 0755)) ErrERR("%s", path); continue; } if (!S_ISDIR(st.st_mode)) Err(_("path component `%s' exists but is not a directory"), path); } } /*--- create_paths() ----------------------------------------------------------------------------*/ /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Open an output file. If file exists, user will be prompted to overwrite unless `overwrite' is nonzero. Returns the file pointer on success, NULL on error. +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ FILE * open_output_file(const char *output_filename, int overwrite, const char *input_filename) { struct stat st; FILE *fp; static int overwrite_all = 0; // Has user requested the [A]ll option? static int overwrite_none = 0; // Has user requested the [N]one option? if (opt_keep_paths) create_paths(output_filename); if (input_filename && !strcmp(output_filename, input_filename)) { fprintf(stderr, "%s: %s (`%s')", output_filename, _("input and output filenames are identical"), input_filename); return (NULL); } if (!stat(output_filename, &st)) { if (!S_ISREG(st.st_mode)) { fprintf(stderr, "%s: %s\n", output_filename, _("file exists and is not a regular file, will not overwrite")); return (NULL); } if (overwrite_none) { fprintf(stderr, "%s: %s\n", output_filename, _("not overwriting file")); return (NULL); } if (!overwrite && !overwrite_all) { char input[5]; if (!isatty(STDOUT_FILENO) || !isatty(STDIN_FILENO)) { fprintf(stderr, "%s: %s\n", output_filename, _("not overwriting file")); return (NULL); } for (;;) { printf("%s `%s'? [y]es, [n]o, [A]ll, [N]one: ", _("Overwrite"), output_filename); fflush(stdout); fgets(input, sizeof(input)-1, stdin); strtrim(input); if (input[1] != '\0') continue; if (*input == 'y' || *input == 'n' || *input == 'A' || *input == 'N') break; } switch (*input) { case 'N': overwrite_none = 1; /* FALLTHROUGH */ case 'n': fprintf(stderr, "%s: %s\n", output_filename, _("not overwriting file")); return (NULL); case 'A': overwrite_all = 1; break; } } } if (!(fp = fopen(output_filename, "wb"))) ErrERR("%s", output_filename); /* Copy permissions from input file to output file */ if (input_filename) copy_file_perms(input_filename, output_filename); return (fp); } /*--- open_output_file() ------------------------------------------------------------------------*/ /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ RENAME_OUTPUT_FILE If an error occurs, renames the output file according to the yEnc spec. The string specified will be placed (in parentheses - UGH) in between the filename and its extension. If the rename succeeds, a pointer to a static buffer containing the new filename is returned. If the rename fails, NULL is returned. +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ char * rename_output_file(const char *filename, const char *errmsg) { char *ext; char base[PATH_MAX]; static char renameto[PATH_MAX]; strncpy(base, filename, sizeof(base)-1); if ((ext = strrchr(base, '.'))) { *(ext++) = '\0'; #if WANT_STRICT_COMPLIANCE snprintf(renameto, sizeof(renameto), "%s(%s).%s", base, errmsg, ext); #else if (strstr(errmsg, "crc")) snprintf(renameto, sizeof(renameto), "%s.bad-crc.%s", base, ext); else if (strstr(errmsg, "size")) snprintf(renameto, sizeof(renameto), "%s.bad-size.%s", base, ext); else snprintf(renameto, sizeof(renameto), "%s.bad-%s.%s", base, errmsg, ext); #endif } else { #if WANT_STRICT_COMPLIANCE snprintf(renameto, sizeof(renameto), "%s(%s)", base, errmsg); #else if (strstr(errmsg, "crc")) snprintf(renameto, sizeof(renameto), "%s.bad-crc", base); else if (strstr(errmsg, "size")) snprintf(renameto, sizeof(renameto), "%s.bad-size", base); else snprintf(renameto, sizeof(renameto), "%s.bad-%s", base, errmsg); #endif } if (rename(filename, renameto) == 0) return (renameto); else return (NULL); } /*--- rename_output_file() ----------------------------------------------------------------------*/ /* vi:set ts=3: */