/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Originally Created by Spencer Murray , 15-Sep-95. * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include #include #include #include #include #include #include typedef int XP_Bool; #define TRUE 1 #define FALSE 0 #define LINUX_GLIBC_2 #include #if !defined(__FreeBSD__) && !defined(MACLINUX) && !defined(LINUX_GLIBC_2) extern char *sys_errlist[]; extern int sys_nerr; #endif int XFE_CANT_MOVE_MAIL = 0; int XFE_CANT_GET_NEW_MAIL_LOCK_FILE_EXISTS = 0; int XFE_CANT_GET_NEW_MAIL_UNABLE_TO_CREATE_LOCK_FILE = 0; int XFE_CANT_GET_NEW_MAIL_SYSTEM_ERROR = 0; int XFE_CANT_MOVE_MAIL_UNABLE_TO_OPEN = 0; int XFE_CANT_MOVE_MAIL_UNABLE_TO_READ = 0; int XFE_CANT_MOVE_MAIL_UNABLE_TO_WRITE = 0; int XFE_THERE_WERE_PROBLEMS_MOVING_MAIL = 0; int XFE_THERE_WERE_PROBLEMS_MOVING_MAIL_EXIT_STATUS = 0; int XFE_THERE_WERE_PROBLEMS_CLEANING_UP = 0; int XFE_MOVEMAIL_FAILURE_SUFFIX = 0; int XFE_UNKNOWN_ERROR_CODE = 0; int XFE_MOVEMAIL_NO_MESSAGES = 0; int XFE_MOVEMAIL_CANT_DELETE_LOCK = 0; #define TMP_SUFFIX ".nslock" #define LOCK_SUFFIX ".lock" #define NAME_LEN 1024 #ifndef BUFSIZ #define BUFSIZ 1024 #endif /* BUFSIZ */ char *XP_GetString(int i) { return NULL; } static void fe_movemail_perror(const char *message) { int e = errno; char *es = 0; char *buf1 = 0; char buf2[512]; char *suffix; int L; if ((unsigned)e < (unsigned)sys_nerr) { es = sys_errlist [e]; } else { snprintf (buf2, sizeof (buf2), XP_GetString( XFE_UNKNOWN_ERROR_CODE ), errno); printf("XFE_UNKNOWN_ERROR_CODE\n"); es = buf2; } suffix = XP_GetString(XFE_MOVEMAIL_FAILURE_SUFFIX); printf("XFE_MOVEMAIL_FAILURE_SUFFIX\n"); if(!suffix) suffix = ""; if(!message) message = ""; L = strlen(message) + strlen(es) + strlen(suffix) + 40; buf1 = (char *) malloc(L); if(!buf1) return; snprintf (buf1, L-1, "%s\n%s\n\n%s", message, es, suffix); #if 0 FE_Alert (buf1); #endif free(buf1); } int fe_MoveMail (char *from, char *to) { XP_Bool succeeded = FALSE; char tmp_file[NAME_LEN]; char lock_file[NAME_LEN]; char spool_dir[NAME_LEN]; char *bp, buf[BUFSIZ]; char msgbuf[1024]; int from_fd = -1; int to_fd = -1; int tmp_fd = -1; int nread, nwritten, nbytes, ntodo; struct stat st; *lock_file = 0; if (!from || !to) return FALSE; if (strlen(from) > NAME_LEN - 1) return FALSE; /* Make spool_dir be "/var/spool/mail" from "/var/spool/mail/$USER". */ strcpy(spool_dir, from); while ((bp = strrchr(spool_dir, '/')) && bp[1] == '\0') *bp = '\0'; if (!bp) return FALSE; *bp = 0; printf("%s\n", spool_dir); /* If we can't write into the directory itself, we can't create files, so we lose. */ if (access(spool_dir, R_OK|W_OK) < 0) { snprintf(msgbuf, sizeof (msgbuf), XP_GetString(XFE_CANT_MOVE_MAIL_UNABLE_TO_WRITE), from); printf("XFE_CANT_MOVE_MAIL_UNABLE_TO_WRITE\n"); fe_movemail_perror(msgbuf); goto FAIL; } /* If the mail-spool file doesn't exist, or is 0-length, bug out. */ if (stat(from, &st) < 0 || st.st_size == 0) { #if 0 NET_Progress (XP_GetString(XFE_MOVEMAIL_NO_MESSAGES)); #endif goto FAIL; } snprintf(tmp_file, sizeof (tmp_file), "%s%s", from, TMP_SUFFIX); if (access(tmp_file, 0) == 0) { /* The tmp file exists; try to get rid of it */ if (unlink(tmp_file) < 0) { snprintf(msgbuf, sizeof (msgbuf), XP_GetString( XFE_CANT_GET_NEW_MAIL_LOCK_FILE_EXISTS ), tmp_file); fe_movemail_perror(msgbuf); goto FAIL; } } snprintf(lock_file, sizeof (lock_file), "%s%s", from, LOCK_SUFFIX); while (1) { int ret; /* First create a real file, $USER.nslock */ tmp_fd = open(tmp_file, O_WRONLY|O_CREAT|O_EXCL, 0666); if (tmp_fd < 0) { snprintf(msgbuf, sizeof (msgbuf), XP_GetString( XFE_CANT_GET_NEW_MAIL_UNABLE_TO_CREATE_LOCK_FILE ), tmp_file); fe_movemail_perror(msgbuf); goto FAIL; } close(tmp_fd); tmp_fd = -1; /* Then make a hard link from $USER.lock to $USER.nslock -- this is the trick to make NFS behave synchronously. */ ret = link(tmp_file, lock_file); /* Now we've (attempted to) make the link. `ret' says whether it was successful. It would have failed if the lock was already being held. Regardless of whether it succeeded, we can now delete $USER.nslock (the thing to which the hard-link points.) */ if (unlink(tmp_file) < 0) { snprintf(msgbuf, sizeof (msgbuf), /* This error message isn't quite right; what it really means is "can't delete $MAIL.nslock", but I guess that could only happen if some other user was the owner of it? Or if it was already gone? Weird... */ XP_GetString(XFE_MOVEMAIL_CANT_DELETE_LOCK), tmp_file); printf("XFE_MOVEMAIL_CANT_DELETE_LOCK\n"); fe_movemail_perror(msgbuf); goto FAIL; } /* If we didn't obtain the lock (== make the hard-link), above, then retry getting it until the file is 60 seconds old... Then get Guido to go over and bust its kneecaps. */ if (ret < 0) { sleep (1); if (stat(lock_file, &st) >= 0) { int current = time(NULL); if (st.st_ctime < current - 60) unlink (lock_file); } } else { /* Got the lock - done waiting. */ break; } } /* All of this junk used to happen in a forked process, but that's not necessary any more (actually, hasn't been for a long time) since we no longer play any setuid/setgid games -- there is no gain to doing this in another fork and waiting for it to complete. */ /* Open the mail spool file for input... */ from_fd = open(from, O_RDWR, 0666); if (from_fd < 0) { int err; if (access(from, W_OK) < 0) /* look again, for right error message */ err = XFE_CANT_MOVE_MAIL_UNABLE_TO_WRITE; else if (access(from, 0) == 0) err = XFE_CANT_MOVE_MAIL_UNABLE_TO_READ; else err = XFE_CANT_MOVE_MAIL_UNABLE_TO_OPEN; snprintf(msgbuf, sizeof (msgbuf), XP_GetString(err), from); fe_movemail_perror(msgbuf); goto FAIL; } /* Open the destination file for output... */ to_fd = open(to, O_WRONLY|O_CREAT|O_EXCL, 0666); if (to_fd < 0) { snprintf(msgbuf, sizeof (msgbuf), XP_GetString( XFE_CANT_MOVE_MAIL_UNABLE_TO_OPEN ), to); fe_movemail_perror(msgbuf); goto FAIL; } /* copy the file */ nbytes = BUFSIZ; while (1) { nread = read(from_fd, buf, nbytes); if (nread < 0) { /* we're busted */ snprintf(msgbuf, sizeof (msgbuf), XP_GetString( XFE_CANT_MOVE_MAIL_UNABLE_TO_READ ), from); fe_movemail_perror(msgbuf); goto FAIL; } if (!nread) { /* we're done */ break; } for (ntodo = nread, bp = buf; ntodo > 0; ntodo -= nwritten, bp += nwritten) { nwritten = write(to_fd, bp, ntodo); if (nwritten < 0) { snprintf(msgbuf, sizeof (msgbuf), XP_GetString( XFE_CANT_MOVE_MAIL_UNABLE_TO_WRITE ), to); fe_movemail_perror(msgbuf); goto FAIL; } } } /* if we made it this far, we're done copying the file contents. First, close and sync the output file. */ if (fsync(to_fd) < 0 || close(to_fd) < 0) { snprintf(msgbuf, sizeof (msgbuf), XP_GetString( XFE_CANT_MOVE_MAIL_UNABLE_TO_WRITE ), to); fe_movemail_perror(msgbuf); goto FAIL; } to_fd = -1; /* Now the output file is closed and sync'ed, so we can truncate the spool file. */ if (ftruncate(from_fd, (off_t)0) < 0) { snprintf(msgbuf, sizeof (msgbuf), XP_GetString( XFE_THERE_WERE_PROBLEMS_CLEANING_UP ), from); fe_movemail_perror(msgbuf); goto FAIL; } succeeded = TRUE; FAIL: if (to_fd >= 0) close(to_fd); if (from_fd >= 0) close(from_fd); if (tmp_fd >= 0) close(tmp_fd); /* Unlink the lock file. If this fails, but we were otherwise successful, then whine about it. Otherwise, we've already presented an error dialog about something else. */ if (*lock_file && unlink(lock_file) < 0 && succeeded) { snprintf(msgbuf, sizeof (msgbuf), XP_GetString( XFE_THERE_WERE_PROBLEMS_CLEANING_UP ), lock_file); fe_movemail_perror(msgbuf); succeeded = FALSE; } return succeeded; } main() { fe_MoveMail ("/var/spool/mail/localguy","/home/localguy/mozilla.mail-recovery"); }