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 #include <sys/stat.h>
00015 
00016 WvAtomicFile::WvAtomicFile(WvStringParm filename, int flags, mode_t create_mode)
00017     : tmp_file(WvString::null)
00018 {
00019     open(filename, flags, create_mode);
00020 }
00021 
00022 WvAtomicFile::~WvAtomicFile()
00023 {
00024     close();
00025 }
00026 
00027 
00028 /* Mimics behaviour of wvfile except that it uses a tmp file and stores the
00029    real name */
00030 bool WvAtomicFile::open(WvStringParm filename, int flags, mode_t create_mode)
00031 {
00032     close();
00033 
00034     atomic_file = filename;
00035 
00036     // Ensure that if the file exists it is a regular file
00037     struct stat st;
00038     if (lstat(atomic_file, &st) == 0 && !S_ISREG(st.st_mode))
00039         return false;
00040  
00041     WvString new_tmp_file("%s/WvXXXXXX", getdirname(filename));
00042     
00043     // Get the current umask and guarantee that mkstemp() creates
00044     // a file with maximal restrictions
00045     mode_t old_umask = ::umask(077);
00046     int tmp_fd = ::mkstemp(new_tmp_file.edit());
00047     if (tmp_fd < 0)
00048         seterr(errno);
00049     ::umask(old_umask);
00050     if (tmp_fd < 0)
00051          return false;
00052  
00053     // Set the permissions as specified using the original umask
00054     // We will only possibly be adding permissions here...
00055     if (::fchmod(tmp_fd, create_mode & ~old_umask) != 0)
00056         seterr(errno);
00057 
00058     if (!WvFile::open(tmp_fd))
00059     {
00060         ::close(tmp_fd);
00061         return false;
00062     }
00063     
00064     tmp_file = new_tmp_file;
00065 
00066     return true;
00067 }
00068 
00069 
00070 void WvAtomicFile::close()
00071 {
00072     WvFdStream::close();
00073     
00074     if (tmp_file)
00075     {
00076         if (::rename(tmp_file, atomic_file) != 0)
00077             ::unlink(tmp_file);
00078         
00079         tmp_file = WvString::null;
00080     }
00081 }
00082 
00083 
00084 bool WvAtomicFile::chmod(mode_t mode)
00085 {
00086     if (getfd() == -1) return false;
00087     
00088     if (fchmod(getfd(), mode) != 0)
00089     {
00090         seterr(errno);
00091         return false;
00092     }
00093     
00094     return true;
00095 }
00096 
00097 
00098 bool WvAtomicFile::chown(uid_t owner, gid_t group)
00099 {
00100     if (getfd() == -1) return false;
00101     
00102     if (fchown(getfd(), owner, group) != 0)
00103     {
00104         seterr(errno);
00105         return false;
00106     }
00107     
00108     return true;
00109 }