]> git.saurik.com Git - apple/security.git/blobdiff - cdsa/cdsa_utilities/AtomicFile.cpp
Security-54.1.7.tar.gz
[apple/security.git] / cdsa / cdsa_utilities / AtomicFile.cpp
index 710c70e830d7def159aff1a80a5483172494467d..f7be07282a2678bd0fe6c4e5c4fe350252f4a9b4 100644 (file)
@@ -41,7 +41,8 @@
 //#include <err.h>
 #include <locale.h>
 #include <stdlib.h>
-#include <string.h>
+#include <cstring>
+#include <sys/param.h>
 
 #elif _USE_IO == _USE_IO_MACOS
 typedef SInt32 ssize_t;
@@ -55,6 +56,7 @@ AtomicFile::AtomicFile(const DbName &inDbName) :
     mWriteFile(nil),
     mWriteFilename(mReadFilename + ",") // XXX Do some more work here like resolving symlinks/aliases etc.
 {
+       debug("atomicfile", "%p construct name=%s", this, mReadFilename.c_str());
     // We only support databases with string names of non-zero length.
     if (inDbName.dbLocation() != nil || inDbName.dbName().length() == 0)
         CssmError::throwMe(CSSMERR_DL_INVALID_DB_LOCATION);
@@ -63,6 +65,7 @@ AtomicFile::AtomicFile(const DbName &inDbName) :
 AtomicFile::~AtomicFile()
 {
     // Assume there are no more running theads in this object.
+       debug("atomicfile", "%p destroyed", this);
 
     // Try hard to clean up as much as possible.
     try
@@ -92,6 +95,7 @@ AtomicFile::~AtomicFile()
 void
 AtomicFile::close()
 {
+       debug("atomicfile", "%p close", this);
     StLock<Mutex> _(mReadLock);
 
     // If we have no read file we have nothing to close.
@@ -174,10 +178,10 @@ AtomicFile::enterRead(const uint8 *&outFileAddress, size_t &outLength)
     // If we never had or no longer have an open read file.  Open it now.
     if (mReadFile == nil)
     {
-        mReadFile = new OpenFile(mReadFilename, false, false, 0);
+        mReadFile = new OpenFile(mReadFilename, false, false, 0, 0);
         mOpenFileMap.insert(OpenFileMap::value_type(mReadFile->versionId(), mReadFile));
     }
-    // Note that mReadFile->isDirty() might actually return true here, but all that mean is
+    // Note that mReadFile->isDirty() might actually return true here, but all that means is
     // that we are looking at data that was commited after we opened the file which might
     // happen in a few miliseconds anyway.
 
@@ -253,7 +257,7 @@ AtomicFile::performDelete()
         // XXX This is a potential infinite loop.
         for (;;)
         {
-            aReadFile = new OpenFile(mReadFilename, true, true, 0);
+            aReadFile = new OpenFile(mReadFilename, true, true, 0, 0);
             if (!aReadFile->isDirty())
                 break;
 
@@ -307,10 +311,10 @@ AtomicFile::enterCreate(FileRef &outWriteRef)
         StLock<Mutex> _(mReadLock);
 
         // Create mReadFilename until the lock has been aquired on a non-dirty file.
-        aReadFile = new OpenFile(mReadFilename, false, true, 1);
+        aReadFile = new OpenFile(mReadFilename, false, true, 1, 0666);
 
         // Open mWriteFile for writing.
-        mWriteFile = new OpenFile(mWriteFilename, true, false, aReadFile->versionId() + 1);
+        mWriteFile = new OpenFile(mWriteFilename, true, false, aReadFile->versionId() + 1, 0666);
 
         // Insert aReadFile into the map (do this after opening mWriteFile just in case that throws).
         mOpenFileMap.insert(OpenFileMap::value_type(-1, aReadFile));
@@ -369,7 +373,7 @@ AtomicFile::enterWrite(const uint8 *&outFileAddress, size_t &outLength, FileRef
         // XXX This is a potential infinite loop.
         for (;;)
         {
-            aReadFile = new OpenFile(mReadFilename, true, true, 0);
+            aReadFile = new OpenFile(mReadFilename, true, true, 0, 0);
             if (!aReadFile->isDirty())
                 break;
 
@@ -383,7 +387,7 @@ AtomicFile::enterWrite(const uint8 *&outFileAddress, size_t &outLength, FileRef
         StLock<Mutex> _(mReadLock);
 
         // Open mWriteFile for writing.
-        mWriteFile = new OpenFile(mWriteFilename, true, false, aReadFile->versionId() + 1);
+        mWriteFile = new OpenFile(mWriteFilename, true, false, aReadFile->versionId() + 1, aReadFile->mode());
 
         // Insert aReadFile into the map (do this after opening mWriteFile just in case that throws).
         mOpenFileMap.insert(OpenFileMap::value_type(-1, aReadFile));
@@ -431,6 +435,7 @@ AtomicFile::enterWrite(const uint8 *&outFileAddress, size_t &outLength, FileRef
 AtomicFile::VersionId
 AtomicFile::commit()
 {
+       debug("atomicfile", "%p commit", this);
     StLock<Mutex> _(mReadLock);
     if (mWriteFile == nil)
         CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
@@ -458,6 +463,7 @@ AtomicFile::commit()
 
         // Close all unused files (in particular aOpenFile) and remove them from mOpenFileMap
         endWrite();
+               debug("atomicfile", "%p commit done", this);
         return aVersionId;
     }
     catch (...)
@@ -468,6 +474,7 @@ AtomicFile::commit()
             unlink(mWriteFilename);
         }catch(...) {}
         endWrite();
+               debug("atomicfile", "%p commit failed, rethrowing", this);
         throw;
     }
 }
@@ -475,6 +482,7 @@ AtomicFile::commit()
 void
 AtomicFile::rollback()
 {
+       debug("atomicfile", "%p rollback", this);
     StLock<Mutex> _(mReadLock);
     if (mWriteFile == nil)
         CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
@@ -490,6 +498,7 @@ AtomicFile::rollback()
         if (mCreating)
             unlink(mReadFilename);
         endWrite();
+               debug("atomicfile", "%p rollback complete", this);
     }
     catch(...)
     {
@@ -499,6 +508,7 @@ AtomicFile::rollback()
             unlink(mWriteFilename);
         }catch(...) {}
         endWrite();
+               debug("atomicfile", "%p rollback failed, rethrowing", this);
         throw;
     }
 }
@@ -614,13 +624,13 @@ AtomicFile::write(OffsetType inOffsetType, uint32 inOffset, const uint8 *inData,
 
 // AtomicFile::OpenFile implementation
 
-AtomicFile::OpenFile::OpenFile(const string &inFilename, bool write, bool lock, VersionId inVersionId) :
+AtomicFile::OpenFile::OpenFile(const string &inFilename, bool write, bool lock, VersionId inVersionId, mode_t mode) :
     mUseCount(0),
     mVersionId(inVersionId),
     mAddress(NULL),
     mLength(0)
 {
-    int flags, mode = 0;
+    int flags;
     if (write && lock)
     {
         flags = O_RDWR;
@@ -629,13 +639,11 @@ AtomicFile::OpenFile::OpenFile(const string &inFilename, bool write, bool lock,
     else if (write && !lock)
     {
         flags = O_WRONLY|O_CREAT|O_TRUNC;
-        mode = 0666;
         mState = Write;
     }
     else if (!write && lock)
     {
         flags = O_WRONLY|O_CREAT|O_TRUNC|O_EXCL;
-        mode = 0666;
         mState = Create;
     }
     else
@@ -643,11 +651,15 @@ AtomicFile::OpenFile::OpenFile(const string &inFilename, bool write, bool lock,
         flags = O_RDONLY;
         mState = Read;
     }
+       debug("atomicfile", "%p openfile(%s,%s%s,%d,0x%x) -> flags=0x%x, state=%d",
+               this, inFilename.c_str(), write ? "write" : "read", lock ? ",lock" : "",
+               inVersionId, mode, flags, mState);
 
     mFileRef = ::open(inFilename.c_str(), flags, mode);
     if (mFileRef == -1)
     {
         int error = errno;
+               debug("atomicfile", "%p openfile open failed(errno=%d)", this, error);
 
 #if _USE_IO == _USE_IO_POSIX
         // Do the obvious error code translations here.
@@ -664,6 +676,8 @@ AtomicFile::OpenFile::OpenFile(const string &inFilename, bool write, bool lock,
 
                                // Now try the open again.
                                mFileRef = ::open(inFilename.c_str(), flags, mode);
+                               debug("atomicfile", "%p openfile reopen %s (%d)",
+                                       this, (mFileRef == -1) ? "failed" : "ok", errno);
                                error = mFileRef == -1 ? errno : 0;
                                if (error == ENOENT)
                                        CssmError::throwMe(CSSM_ERRCODE_OS_ACCESS_DENIED);
@@ -777,13 +791,17 @@ AtomicFile::OpenFile::~OpenFile()
 void
 AtomicFile::OpenFile::close()
 {
+       IFDEBUG(if (mState != Closed) debug("atomicfile", "%p openfile closing(ref=%d)",
+               this, mFileRef));
     int error = 0;
     if (mAddress != NULL)
     {
 #if _USE_IO == _USE_IO_POSIX
+               debug("atomicfile", "%p openfile is unmapping %p:%ld", this, mAddress, mLength);
         if (::munmap(const_cast<uint8 *>(mAddress), mLength) == -1)
             error = errno;
 #else
+               debug("atomicfile", "%p openfile deleting %p", this, mAddress);
                delete[] mAddress;
 #endif
 
@@ -842,6 +860,16 @@ AtomicFile::OpenFile::unlock()
 #endif
 }
 
+mode_t
+AtomicFile::OpenFile::mode()
+{
+       struct stat st;
+       if (::fstat(mFileRef, &st) == -1)
+               UnixError::throwMe(errno);
+       return st.st_mode;
+}
+
+
 AtomicFile::VersionId
 AtomicFile::OpenFile::readVersionId()
 {
@@ -913,37 +941,31 @@ AtomicFile::OpenFile::writeVersionId(VersionId inVersionId)
 void
 AtomicFile::OpenFile::mkpath(const std::string &inFilename)
 {
-       char *path = const_cast<char *>(inFilename.c_str()); // @@@ Const_cast is a lie!!!
+       const char *path = inFilename.c_str();
        struct stat sb;
-       char *slash;
-    mode_t dir_mode = (0777 & ~umask(0)) | S_IWUSR | S_IXUSR;
-
-       slash = path;
+       char dirPath[MAXPATHLEN];
+       size_t slash = 0;
 
        for (;;)
        {
-               slash += strspn(slash, "/");
-               slash += strcspn(slash, "/");
+               slash += strspn(path + slash, "/");
+               slash += strcspn(path + slash, "/");
 
-               if (*slash == '\0')
+               if (path[slash] == '\0')
                        break;
 
-               *slash = '\0';
+               if (slash >= MAXPATHLEN)
+                       UnixError::throwMe(ENAMETOOLONG);
+               strncpy(dirPath, path, slash);
+               dirPath[slash] = '\0';
 
-               if (stat(path, &sb))
+               if (stat(dirPath, &sb))
                {
-                       if (errno != ENOENT || mkdir(path, dir_mode))
-                               UnixError::throwMe(errno);
-                       /* The mkdir() and umask() calls both honor only the low
-                          nine bits, so if you try to set a mode including the
-                          sticky, setuid, setgid bits you lose them. So chmod().  */
-                       if (chmod(path, dir_mode) == -1)
+                       if (errno != ENOENT || mkdir(dirPath, 0777))
                                UnixError::throwMe(errno);
                }
                else if (!S_ISDIR(sb.st_mode))
                        CssmError::throwMe(CSSM_ERRCODE_OS_ACCESS_DENIED);  // @@@ Should be is a directory
-
-               *slash = '/';
        }
 }