static char rcsid[] = "@(#)$Id: file_util.c,v 1.10 2006/04/09 07:37:06 hurtta Exp $"; /****************************************************************************** * The Elm (ME+) Mail System - $Revision: 1.10 $ $State: Exp $ * * Modified by: Kari Hurtta * (was hurtta+elm@ozone.FMI.FI) ****************************************************************************** * Copied from src/file_util.c, which have following text: * * The Elm Mail System * * Copyright (c) 1988-1992 USENET Community Trust * Copyright (c) 1986,1987 Dave Taylor *****************************************************************************/ #include "headers.h" #include "s_me.h" #include "s_elm.h" #include #ifndef ANSI_C extern int errno; #endif DEBUG_VAR(Debug,__FILE__,"file"); long file_bytes(name) CONST char *name; { /** return the number of bytes in the specified file. This is to check to see if new mail has arrived.... (also see "fsize()" to see how we can get the same information on an opened file descriptor slightly more quickly) **/ int ok = 1; struct stat buffer; if (stat(name, &buffer) != 0) { int err = errno; if (err != ENOENT) { lib_error(CATGETS(elm_msg_cat, MeSet, MeFileNoStat, "File %.30s: %.40s"), name,error_description(err)); DPRINT(Debug,1,(&Debug, "file_bytes: errno %s on fstat of file %s\n", error_description(err), name)); return -1L; } else ok = 0; } return(ok ? (long) buffer.st_size : 0L); } static struct stat saved_buf; /* * Don't take chances that a file name is really longer than SLEN. * You'll just pollute the memory right after the allocated space * if you have MAXPATHLEN of 1024 (_PATH_MAX in POSIX). */ static char saved_fname[VERY_LONG_STRING]; int save_file_stats(fname) CONST char *fname; { /* if fname exists, save the owner, group, mode and filename. * otherwise flag nothing saved. Return 0 if saved, else -1. */ if(stat(fname, &saved_buf) != -1) { strfcpy(saved_fname, fname, sizeof saved_fname); DPRINT(Debug,2,(&Debug, "** saved stats for file owner = %d group = %d mode = %o %s **\n", saved_buf.st_uid, saved_buf.st_gid, saved_buf.st_mode, fname)); return(0); } DPRINT(Debug,2,(&Debug, "** couldn't save stats for file %s [errno=%d] **\n", fname, errno)); return(-1); } int restore_file_stats(fname) CONST char *fname; { /* if fname matches the saved file name, set the owner and group * of fname to the saved owner, group and mode, * else to the userid and groupid of the user and to 700. * Return -1 if the either mode or owner/group not set * 0 if the default values were used * 1 if the saved values were used */ int old_umask, i, new_mode, new_owner, new_group, ret_code; struct stat testbuf; new_mode = mail_permissions; new_owner = userid; new_group = groupid; ret_code = 0; if(strcmp(fname, saved_fname) == 0) { new_mode = saved_buf.st_mode & 0777; /* Restore also special bits if file is NOT executable */ if (!(saved_buf.st_mode & 0111)) { new_mode |= saved_buf.st_mode & 07000; DPRINT(Debug,2,(&Debug, "** not excutable -- restore also special modes\n")); } new_owner = saved_buf.st_uid; new_group = saved_buf.st_gid; ret_code = 1; } DPRINT(Debug,2,(&Debug, "** %s file stats for %s **\n", (ret_code ? "restoring" : "setting"), fname)); old_umask = umask(0); if((i = chmod(fname, new_mode)) == -1) ret_code = -1; DPRINT(Debug,2,(&Debug, "** chmod(%s, %05o) returns %d [errno=%d] **\n", fname, new_mode, i, errno)); (void) umask(old_umask); if(stat(fname, &testbuf) != -1) { DPRINT(Debug,2,(&Debug, "** stats for file owner = %d group = %d mode = %o %s **\n", testbuf.st_uid, testbuf.st_gid, testbuf.st_mode, fname)); /* Don't do chown because it resets special modes, if not * neccessary */ if (new_owner == testbuf.st_uid && new_group == testbuf.st_gid) { DPRINT(Debug,2,(&Debug, "** Owner correct -- chown not needed.\n")); } else { #ifdef BSD_TYPE /* * Chown is restricted to root on BSD unix */ (void) elm_chown(fname, new_owner, new_group); #else # ifdef _PC_CHOWN_RESTRICTED /* * Chown may or may not be restricted to root in SVR4, if it is, * then need to copy must be true, and no restore of permissions * should be performed. */ if (!pathconf(fname, _PC_CHOWN_RESTRICTED)) { # endif if((i = elm_chown(fname, new_owner, new_group)) == -1) ret_code = -1; DPRINT(Debug,2,(&Debug, "** elm_chown(%s, %d, %d) returns %d [errno=%d] **\n", fname, new_owner, new_group, i, errno)); # ifdef _PC_CHOWN_RESTRICTED } else { if( -1 == (i = elm_chown(fname, new_owner, new_group))) { DPRINT(Debug,7,(&Debug, "** elm_chown(%s, %d, %d) returns %d [errno=%d] IGNORED **\n", fname, new_owner, new_group, i, errno)); } } # endif /* _PC_CHOWN_RESTRICTED */ #endif /* BSD_TYPE */ } } if(stat(fname, &testbuf) != -1) { DPRINT(Debug,2, (&Debug, "** stats for file owner = %d group = %d mode = %o %s **\n", testbuf.st_uid, testbuf.st_gid, testbuf.st_mode, fname)); } return(ret_code); } /* Open and possible creates file for updates */ FILE *open_or_create(name) CONST char *name; { FILE *fp; int fd = open(name, O_RDWR | O_CREAT,0600); if (fd < 0) { int err = errno; DPRINT(Debug,1,(&Debug, "open_or_create: could not open file %s\n\tError: %s\n", name, error_description(err))); return NULL; } if (! (fp = fdopen(fd, "r+"))) { DPRINT(Debug,1,(&Debug, "open_or_create: could not fdopen(%d) file %s\n", fd,name)); close(fd); return NULL; } return fp; } int copy_to_fh(from, to) FILE *from; FILE *to; { char buffer[VERY_LONG_STRING]; int len; rewind(from); while ((len = fread(buffer, 1, VERY_LONG_STRING, from)) > 0) { if (fwrite(buffer, 1, len, to) != len) { int err = errno; lib_error(CATGETS(elm_msg_cat, ElmSet, ElmWriteFailedCopy, "Write failed in copy: %s: %s"), to, error_description(err)); /* * NEVER close anything just at whim!! * If the file has been locked using fcntl() or lockf() * YOU WILL DROP ALL LOCKS refering to the file. */ fflush(to); return(1); } } if (ferror(from)) { int err = errno; lib_error(CATGETS(elm_msg_cat, ElmSet, ElmReadFailedCopy2, "Read failed in copy: %s"), error_description(err)); fflush(to); return(1); } if (fflush(to) == EOF) { int err = errno; lib_error(CATGETS(elm_msg_cat, ElmSet, ElmFlushFailedCopy, "Flush failed in copy: %s"), error_description(err)); return(1); } return 0; } int copy1(from, to, isspool) FILE *from; char *to; int isspool; { /** this routine copies a specified file to the destination specified. Non-zero return code indicates that something dreadful happened! **/ FILE *to_file; int code; DPRINT(Debug,1,(&Debug, "Copy: to='%s'\n", to)); if (!isspool) { int err = can_open(to, "w"); if (err) { DPRINT(Debug,1,(&Debug, "Error: could not open %s for writing (copy -- can_open)\n", to)); lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCouldNotOpenFile, "Could not open file %s."), to); return(1); } } if ((to_file = fopen(to, "w")) == NULL) { DPRINT(Debug,1,(&Debug, "Error: could not open %s for writing (copy)\n", to)); lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCouldNotOpenFile, "Could not open file %s."), to); return(1); } code = copy_to_fh(from,to_file); if (fclose(to_file) == EOF) { int err = errno; lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCloseFailedCopy, "Close failed in copy: %s: %s"), to, error_description(err)); return(1); } if (!isspool) (void) elm_chown( to, userid, groupid); return(code); } int elm_chown(file, userid, groupid) CONST char *file; int userid, groupid; { #ifdef CHOWN_NEG1 int status; status = chown(file, -1, groupid); chown(file, userid, -1); return(status); #else return(chown(file, userid, groupid)); #endif } /* * Local Variables: * mode:c * c-basic-offset:4 * buffer-file-coding-system: iso-8859-1 * End: */