#include <copyfile.h>
#include <sandbox.h>
#include <set>
+#include <assert.h>
#define kAtomicFileMaxBlockSize INT_MAX
{
}
-// Aquire the write lock and remove the file.
+// Acquire the write lock and remove the file.
void
AtomicFile::performDelete()
{
if (::unlink(mPath.c_str()) != 0)
{
int error = errno;
- secdebug("atomicfile", "unlink %s: %s", mPath.c_str(), strerror(error));
+ secinfo("atomicfile", "unlink %s: %s", mPath.c_str(), strerror(error));
if (error == ENOENT)
CssmError::throwMe(CSSMERR_DL_DATASTORE_DOESNOT_EXIST);
else
::unlink(mLockFilePath.c_str());
}
-// Aquire the write lock and rename the file (and bump the version and stuff).
+// Acquire the write lock and rename the file (and bump the version and stuff).
void
AtomicFile::rename(const std::string &inNewPath)
{
if (::rename(path, newPath) != 0)
{
int error = errno;
- secdebug("atomicfile", "rename(%s, %s): %s", path, newPath, strerror(error));
+ secinfo("atomicfile", "rename(%s, %s): %s", path, newPath, strerror(error));
UnixError::throwMe(error);
}
}
if (fileRef == -1)
{
int error = errno;
- secdebug("atomicfile", "open %s: %s", path, strerror(error));
+ secinfo("atomicfile", "open %s: %s", path, strerror(error));
// Do the obvious error code translations here.
// @@@ Consider moving these up a level.
// Now that we have created the lock and the new db file create a tempfile
// object.
RefPointer<AtomicTempFile> temp(new AtomicTempFile(*this, lock, mode));
- secdebug("atomicfile", "%p created %s", this, path);
+ secinfo("atomicfile", "%p created %s", this, path);
return temp;
}
catch (...)
// Creating the temp file failed so remove the db file we just created too.
if (::unlink(path) == -1)
{
- secdebug("atomicfile", "unlink %s: %s", path, strerror(errno));
+ secnotice("atomicfile", "unlink %s: %s", path, strerror(errno));
}
throw;
}
if (::stat(path, &st) == -1)
{
int error = errno;
- secdebug("atomicfile", "stat %s: %s", path, strerror(error));
+ secinfo("atomicfile", "stat %s: %s", path, strerror(error));
UnixError::throwMe(error);
}
return st.st_mode;
int result = sandbox_check(getpid(), "file-read-data", (sandbox_filter_type) (SANDBOX_FILTER_PATH | SANDBOX_CHECK_NO_REPORT), name);
if (result != 0)
{
+ secdebug("atomicfile", "sandboxing rejected read access to %s", name);
return -1;
}
}
int result = sandbox_check(getpid(), "file-write-data", (sandbox_filter_type) (SANDBOX_FILTER_PATH | SANDBOX_CHECK_NO_REPORT), name);
if (result != 0)
{
+ secdebug("atomicfile", "sandboxing rejected write access to %s", name);
return -1;
}
}
mPath(inPath),
mFileRef(-1),
mBuffer(NULL),
- mLength(0),
- mIsMapped(isLocal)
+ mLength(0)
{
}
{
if (mFileRef >= 0)
{
- AtomicFile::rclose(mFileRef);
- secdebug("atomicfile", "%p closed %s", this, mPath.c_str());
+ // In release mode, the assert() is compiled out so rv may be unused.
+ __unused int rv = AtomicFile::rclose(mFileRef);
+ assert(rv == 0);
+ secinfo("atomicfile", "%p closed %s", this, mPath.c_str());
}
if (mBuffer)
{
- secdebug("atomicfile", "%p free %s buffer %p", this, mPath.c_str(), mBuffer);
+ secinfo("atomicfile", "%p free %s buffer %p", this, mPath.c_str(), mBuffer);
unloadBuffer();
}
}
const char *path = mPath.c_str();
if (mFileRef >= 0)
{
- secdebug("atomicfile", "open %s: already open, closing and reopening", path);
+ secinfo("atomicfile", "open %s: already open, closing and reopening", path);
close();
}
if (mFileRef == -1)
{
int error = errno;
- secdebug("atomicfile", "open %s: %s", path, strerror(error));
+ secinfo("atomicfile", "open %s: %s", path, strerror(error));
// Do the obvious error code translations here.
// @@@ Consider moving these up a level.
else
{
int error = errno;
- secdebug("atomicfile", "lseek(%s, END): %s", path, strerror(error));
+ secinfo("atomicfile", "lseek(%s, END): %s", path, strerror(error));
AtomicFile::rclose(mFileRef);
+ mFileRef = -1;
UnixError::throwMe(error);
}
- secdebug("atomicfile", "%p opened %s: %qd bytes", this, path, mLength);
+ secinfo("atomicfile", "%p opened %s: %qd bytes", this, path, mLength);
return mLength;
}
void
AtomicBufferedFile::unloadBuffer()
{
- if (!mIsMapped)
- {
- delete [] mBuffer;
- }
- else
- {
- munmap(mBuffer, (size_t)mLength);
- }
+ if(mBuffer) {
+ delete [] mBuffer;
+ mBuffer = NULL;
+ }
}
//
// Load the contents of the file into memory.
-// If we are on a local file system, we mmap the file. Otherwise, we
-// read it all into memory
void
AtomicBufferedFile::loadBuffer()
{
- if (!mIsMapped)
- {
- // make a buffer big enough to hold the entire file
- mBuffer = new uint8[mLength];
- lseek(mFileRef, 0, SEEK_SET);
- ssize_t pos = 0;
-
- ssize_t bytesToRead = (ssize_t)mLength;
- while (bytesToRead > 0)
- {
- ssize_t bytesRead = ::read(mFileRef, mBuffer + pos, bytesToRead);
- if (bytesRead == -1)
- {
- if (errno != EINTR)
- {
- int error = errno;
- secdebug("atomicfile", "lseek(%s, END): %s", mPath.c_str(), strerror(error));
- AtomicFile::rclose(mFileRef);
- UnixError::throwMe(error);
- }
- }
- else
- {
- bytesToRead -= bytesRead;
- pos += bytesRead;
- }
- }
- }
- else
- {
- // mmap the buffer into place
- mBuffer = (uint8*) mmap(NULL, (size_t)mLength, PROT_READ, MAP_PRIVATE, mFileRef, 0);
- if (mBuffer == (uint8*) -1)
- {
- int error = errno;
- secdebug("atomicfile", "lseek(%s, END): %s", mPath.c_str(), strerror(error));
- AtomicFile::rclose(mFileRef);
- UnixError::throwMe(error);
- }
- }
+ // make a buffer big enough to hold the entire file
+ mBuffer = new uint8[(size_t) mLength];
+ if(lseek(mFileRef, 0, SEEK_SET) < 0) {
+ int error = errno;
+ secinfo("atomicfile", "lseek(%s, BEGINNING): %s", mPath.c_str(), strerror(error));
+ UnixError::throwMe(error);
+ }
+ ssize_t pos = 0;
+
+ ssize_t bytesToRead = (ssize_t)mLength;
+ while (bytesToRead > 0)
+ {
+ ssize_t bytesRead = ::read(mFileRef, mBuffer + pos, bytesToRead);
+ if (bytesRead == -1)
+ {
+ if (errno != EINTR)
+ {
+ int error = errno;
+ secinfo("atomicfile", "read(%s, %zd): %s", mPath.c_str(), bytesToRead, strerror(error));
+ AtomicFile::rclose(mFileRef);
+ mFileRef = -1;
+ UnixError::throwMe(error);
+ }
+ }
+ else
+ {
+ bytesToRead -= bytesRead;
+ pos += bytesRead;
+ }
+ }
}
{
if (mFileRef < 0)
{
- secdebug("atomicfile", "read %s: file yet not opened, opening", mPath.c_str());
+ secinfo("atomicfile", "read %s: file yet not opened, opening", mPath.c_str());
open();
}
off_t bytesLeft = inLength;
if (mBuffer)
{
- secdebug("atomicfile", "%p free %s buffer %p", this, mPath.c_str(), mBuffer);
+ secinfo("atomicfile", "%p free %s buffer %p", this, mPath.c_str(), mBuffer);
unloadBuffer();
}
loadBuffer();
- secdebug("atomicfile", "%p allocated %s buffer %p size %qd", this, mPath.c_str(), mBuffer, bytesLeft);
+ secinfo("atomicfile", "%p allocated %s buffer %p size %qd", this, mPath.c_str(), mBuffer, bytesLeft);
off_t maxEnd = inOffset + inLength;
if (maxEnd > mLength)
{
if (mFileRef < 0)
{
- secdebug("atomicfile", "close %s: already closed", mPath.c_str());
+ secinfo("atomicfile", "close %s: already closed", mPath.c_str());
}
else
{
if (result == -1)
{
int error = errno;
- secdebug("atomicfile", "close %s: %s", mPath.c_str(), strerror(errno));
+ secnotice("atomicfile", "close %s: %s", mPath.c_str(), strerror(errno));
UnixError::throwMe(error);
}
- secdebug("atomicfile", "%p closed %s", this, mPath.c_str());
+ secinfo("atomicfile", "%p closed %s", this, mPath.c_str());
}
}
if (mFileRef == -1)
{
int error = errno;
- secdebug("atomicfile", "open %s: %s", path, strerror(error));
+ secnotice("atomicfile", "create %s: %s", path, strerror(error));
// Do the obvious error code translations here.
// @@@ Consider moving these up a level.
if (::fchmod(mFileRef, mode))
{
int error = errno;
- secdebug("atomicfile", "fchmod %s: %s", path, strerror(error));
+ secnotice("atomicfile", "fchmod %s: %s", path, strerror(error));
UnixError::throwMe(error);
}
}
- secdebug("atomicfile", "%p created %s", this, path);
+ secinfo("atomicfile", "%p created %s", this, path);
}
void
if (pos == -1)
{
int error = errno;
- secdebug("atomicfile", "lseek(%s, %qd): %s", mPath.c_str(), inOffset, strerror(error));
+ secnotice("atomicfile", "lseek(%s, %qd): %s", mPath.c_str(), inOffset, strerror(error));
UnixError::throwMe(error);
}
}
if (error == EINTR)
{
// We got interrupted by a signal, so try again.
- secdebug("atomicfile", "write %s: interrupted, retrying", mPath.c_str());
+ secnotice("atomicfile", "write %s: interrupted, retrying", mPath.c_str());
continue;
}
- secdebug("atomicfile", "write %s: %s", mPath.c_str(), strerror(error));
+ secnotice("atomicfile", "write %s: %s", mPath.c_str(), strerror(error));
UnixError::throwMe(error);
}
// Write returning 0 is bad mmkay.
if (bytesWritten == 0)
{
- secdebug("atomicfile", "write %s: 0 bytes written", mPath.c_str());
+ secnotice("atomicfile", "write %s: 0 bytes written", mPath.c_str());
CssmError::throwMe(CSSMERR_DL_INTERNAL_ERROR);
}
{
if (mFileRef < 0)
{
- secdebug("atomicfile", "fsync %s: already closed", mPath.c_str());
+ secnotice("atomicfile", "fsync %s: already closed", mPath.c_str());
}
else
{
if (result == -1)
{
int error = errno;
- secdebug("atomicfile", "fsync %s: %s", mPath.c_str(), strerror(errno));
+ secnotice("atomicfile", "fsync %s: %s", mPath.c_str(), strerror(errno));
UnixError::throwMe(error);
}
- secdebug("atomicfile", "%p fsynced %s", this, mPath.c_str());
+ secinfo("atomicfile", "%p fsynced %s", this, mPath.c_str());
}
}
{
if (mFileRef < 0)
{
- secdebug("atomicfile", "close %s: already closed", mPath.c_str());
+ secnotice("atomicfile", "close %s: already closed", mPath.c_str());
}
else
{
if (result == -1)
{
int error = errno;
- secdebug("atomicfile", "close %s: %s", mPath.c_str(), strerror(errno));
+ secnotice("atomicfile", "close %s: %s", mPath.c_str(), strerror(errno));
UnixError::throwMe(error);
}
- secdebug("atomicfile", "%p closed %s", this, mPath.c_str());
+ secinfo("atomicfile", "%p closed %s", this, mPath.c_str());
}
}
s = copyfile_state_alloc();
if(copyfile(newPath, oldPath, s, COPYFILE_SECURITY | COPYFILE_NOFOLLOW) == -1) // Not fatal
- secdebug("atomicfile", "copyfile (%s, %s): %s", oldPath, newPath, strerror(errno));
+ secnotice("atomicfile", "copyfile (%s, %s): %s", oldPath, newPath, strerror(errno));
copyfile_state_free(s);
// END <rdar://problem/6991037>
if (::rename(oldPath, newPath) == -1)
{
int error = errno;
- secdebug("atomicfile", "rename (%s, %s): %s", oldPath, newPath, strerror(errno));
+ secnotice("atomicfile", "rename (%s, %s): %s", oldPath, newPath, strerror(errno));
UnixError::throwMe(error);
}
+ secnotice("atomicfile", "%p commited %s to %s", this, oldPath, newPath);
+
// Unlock the lockfile
mLockedFile = NULL;
-
- secdebug("atomicfile", "%p commited %s", this, oldPath);
}
catch (...)
{
const char *path = mPath.c_str();
if (::unlink(path) == -1)
{
- secdebug("atomicfile", "unlink %s: %s", path, strerror(errno));
+ secnotice("atomicfile", "unlink %s: %s", path, strerror(errno));
// rollback can't throw
}
const char *path = mFile.path().c_str();
if (::unlink(path) == -1)
{
- secdebug("atomicfile", "unlink %s: %s", path, strerror(errno));
+ secnotice("atomicfile", "unlink %s: %s", path, strerror(errno));
// rollback can't throw
}
}
int result = flock(mLockFile, LOCK_EX);
IFDEBUG(double endTime = GetTime());
- IFDEBUG(secdebug("atomictime", "Waited %.4f milliseconds for file lock", (endTime - startTime) * 1000.0));
+ IFDEBUG(secnotice("atomictime", "Waited %.4f milliseconds for file lock", (endTime - startTime) * 1000.0));
// errors at this point are bad
if (result == -1)
{
int error = errno;
::syslog(LOG_ERR, "Couldn't create temp file %s: %s", fullname.c_str(), strerror(error));
- secdebug("atomicfile", "Couldn't create temp file %s: %s", fullname.c_str(), strerror(error));
+ secnotice("atomicfile", "Couldn't create temp file %s: %s", fullname.c_str(), strerror(error));
UnixError::throwMe(error);
}
else
doSyslog = true;
- secdebug("atomicfile", "Locking %s", path); /* in order to cater for clock skew: get */
+ secinfo("atomicfile", "Locking %s", path); /* in order to cater for clock skew: get */
if (!xcreat(path, mode, t)) /* time t from the filesystem */
{
/* lock acquired, hurray! */
{
triedforce=true;
::syslog(LOG_ERR, "Forced unlock denied on %s", path);
- secdebug("atomicfile", "Forced unlock denied on %s", path);
+ secnotice("atomicfile", "Forced unlock denied on %s", path);
}
else
{
::syslog(LOG_ERR, "Forcing lock on %s", path);
- secdebug("atomicfile", "Forcing lock on %s", path);
+ secnotice("atomicfile", "Forcing lock on %s", path);
sleep(16 /* DEFsuspend */);
break;
}
case ENAMETOOLONG: /* Filename is too long, shorten and retry */
if (mPath.size() > mDir.size() + 8)
{
- secdebug("atomicfile", "Truncating %s and retrying lock", path);
+ secnotice("atomicfile", "Truncating %s and retrying lock", path);
mPath.erase(mPath.end() - 1);
path = mPath.c_str();
/* Reset retry counter. */
{
int error = errno;
::syslog(LOG_ERR, "Lock failure on %s: %s", path, strerror(error));
- secdebug("atomicfile", "Lock failure on %s: %s", path, strerror(error));
+ secnotice("atomicfile", "Lock failure on %s: %s", path, strerror(error));
UnixError::throwMe(error);
}
}
const char *path = mPath.c_str();
if (::unlink(path) == -1)
{
- secdebug("atomicfile", "unlink %s: %s", path, strerror(errno));
+ secnotice("atomicfile", "unlink %s: %s", path, strerror(errno));
// unlock can't throw
}
}