WvStreams
wvatomicfile.cc
00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2005 Net Integration Technologies, Inc.
00004  *
00005  * Wrapper class for WvFile for automic file creation.  Any files that
00006  *  are guaranteed to be automic will completely write over any existing
00007  *  file on close.
00008 */
00009 
00010 #include "wvatomicfile.h"
00011 #include "wvfileutils.h"
00012 #include "wvstrutils.h"
00013 
00014 WvAtomicFile::WvAtomicFile(WvStringParm filename, int flags, mode_t create_mode)
00015     : tmp_file(WvString::null)
00016 {
00017     open(filename, flags, create_mode);
00018 }
00019 
00020 WvAtomicFile::~WvAtomicFile()
00021 {
00022     close();
00023 }
00024 
00025 
00026 /* Mimics behaviour of wvfile except that it uses a tmp file and stores the
00027    real name */
00028 bool WvAtomicFile::open(WvStringParm filename, int flags, mode_t create_mode)
00029 {
00030     close();
00031 
00032     atomic_file = filename;
00033 
00034     // Ensure that if the file exists it is a regular file
00035     struct stat st;
00036     if (lstat(atomic_file, &st) == 0 && !S_ISREG(st.st_mode))
00037         return false;
00038  
00039     WvString new_tmp_file("%s/WvXXXXXX", getdirname(filename));
00040     
00041     // Get the current umask and guarantee that mkstemp() creates
00042     // a file with maximal restrictions
00043     mode_t old_umask = ::umask(077);
00044     int tmp_fd = ::mkstemp(new_tmp_file.edit());
00045     if (tmp_fd < 0)
00046         seterr(errno);
00047     ::umask(old_umask);
00048     if (tmp_fd < 0)
00049          return false;
00050  
00051     // Set the permissions as specified using the original umask
00052     // We will only possibly be adding permissions here...
00053     if (::fchmod(tmp_fd, create_mode & ~old_umask) != 0)
00054         seterr(errno);
00055 
00056     if (!WvFile::open(tmp_fd))
00057     {
00058         ::close(tmp_fd);
00059         return false;
00060     }
00061     
00062     tmp_file = new_tmp_file;
00063 
00064     return true;
00065 }
00066 
00067 
00068 void WvAtomicFile::close()
00069 {
00070     WvFdStream::close();
00071     
00072     if (tmp_file)
00073     {
00074         if (::rename(tmp_file, atomic_file) != 0)
00075             ::unlink(tmp_file);
00076         
00077         tmp_file = WvString::null;
00078     }
00079 }
00080 
00081 
00082 bool WvAtomicFile::chmod(mode_t mode)
00083 {
00084     if (getfd() == -1) return false;
00085     
00086     if (fchmod(getfd(), mode) != 0)
00087     {
00088         seterr(errno);
00089         return false;
00090     }
00091     
00092     return true;
00093 }
00094 
00095 
00096 bool WvAtomicFile::chown(uid_t owner, gid_t group)
00097 {
00098     if (getfd() == -1) return false;
00099     
00100     if (fchown(getfd(), owner, group) != 0)
00101     {
00102         seterr(errno);
00103         return false;
00104     }
00105     
00106     return true;
00107 }