X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/bac41a7b9a0a9254fa30f8bb6e6038ab71a483e2..a66d0d4aa363c2f8ee16aee8810732ae89bc0608:/cdsa/cdsa_utilities/AtomicFile.cpp?ds=sidebyside diff --git a/cdsa/cdsa_utilities/AtomicFile.cpp b/cdsa/cdsa_utilities/AtomicFile.cpp index 710c70e8..f7be0728 100644 --- a/cdsa/cdsa_utilities/AtomicFile.cpp +++ b/cdsa/cdsa_utilities/AtomicFile.cpp @@ -41,7 +41,8 @@ //#include #include #include -#include +#include +#include #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 _(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 _(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 _(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 _(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 _(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(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(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 = '/'; } }